2016-11-12 9 views
0

Я бы хотел выполнить проверку, чтобы проверить, действительно ли sudoku действительна на Java, и наткнулся на нее (http://leetcode.tgic.me/valid-sudoku/index.html).Как реализовать проверку, действительно ли судоку действительна на Java?

Я понимаю, как это проверка строк и столбцов, а для валидатора 3x3 сеток:

34   for(x = 0; x < mx; x += 3){ 
35    for(y = 0; y < my; y += 3){ 
36     
37     HashSet<Character> block = new HashSet<Character>(); 
38     
39     for(int offset = 0; offset < 9; offset++){ 
40      int ox = offset % 3; 
41      int oy = offset/3; 
42      
43      char c = board[x + ox][y + oy]; 
44      if(c != '.'){ 
45       if(block.contains(c)) return false; 
46      
47       block.add(c); 
48      } 
49     } 
50    } 
51   } 

offset Что такое и как это помогает проверить каждую ячейку в сетке 3x3? Я Brute заставил его и попытался x=0, y=0, offset=0 и offset=1 первый, но offset=1 дает int ox = 1%3 = 1; и int oy = 1/3, поэтому board[0 + 1][0+(1/3)] = board[1][1/3], а что клетка [1/3] представляют и так далее?

ответ

1

при разделении п на т, оба INT в (литералы или переменные), результат также ИНТ, поэтому 1/3 -> 0 Поэтому, когда смещение == 0 => вол = 0, ой = 0 смещение == 1 => ox = 1, oy = 0 offset == 2 => ox = 2, oy = 0 offset == 3 -> ox = 0, oy = 1 ... отсюда вы будет цикл красиво из 3 строк и 3 столбцов

+0

Получил! Прежде чем я приму ответ и вернемся, еще несколько вопросов. Как получается, что 'int ox = offset% 3;' и 'int oy = offset/3;' помогают прокручивать сетку 3x3? И почему «HashSet» над другими? –

+0

также, тогда в случае сказать '0,6' будет округлено до 1? или все еще быть '0'? –

+0

@KuNole Добавьте 'System.out.println', чтобы увидеть, какие' x + ox' и 'y + oy' находятся в точке, где он получает значение от' board'. Тогда вы сможете увидеть. – ajb

0

Ваш HashSet подход выглядит довольно хорошо, но нужно немного тонкой настройки ...

предположение: когда первый блок является дублированием, и одно и то же положение во всех блоках также не содержит дублирования, затем разрешается судоку.

В вашем внешнем цикле вы должны пройти только значения первого блока.

Вы должны добавить текущее значение на «обратный набор первого блока» и проверьте, что все блоки имеют различное количество в том же положении, с помощью внутреннего контура со своим собственным «проверки набора»:

First iteration 
1## 2## 3## 
### ### ### 
### ### ### 

4## 5## 5## 
### ### ### 
### ### ### 

7## 8## 9## 
### ### ### 
### ### ### 
firstBlock: [1] 

second iteration 
#2# #3# #4# 
### ### ### 
### ### ### 

#5# #6# #7# 
### ### ### 
### ### ### 

#8# #9# #1# 
### ### ### 
### ### ### 
firstBlock: [1,2] 

Большой трюк заключается в том, чтобы избежать отдельных петель для координат x и y.

Поскольку Java является объектно-ориентированный язык программирования я предлагаю использовать объекты для определения координат. Мы могли бы держать их в массиве (установить закладку, я обычно говорю «Коллекция» вместо этого ...) и повторить ее с помощью простого контура печки ...

Также мы должны иметь дело с количеством исправленных объектов мы знаем заранее (там 9 блоков с 9 позиций в каждой ...) поэтому я предлагаю использовать Java enums так: так что вы логика должна выглядеть следующим образом:

public class SudokuCheck { 
    enum SudokuPosition { 
     p11(0, 0), p12(0, 1), p13(0, 2), 
     p21(1, 0), p22(1, 1), p23(1, 2), 
     p31(2, 0), p32(2, 1), p33(2, 2); 

     private final int x; 
     private final int y; 
     SudokuPosition(int x, int y) { 
      this.x = x; 
      this.y = y; 
     } 
     public int getX() {return x;}  
     public int getY() {return y;} 
    } 

    boolean check(int[][] sudoku) { 
     Set<Integer> firstBlockUniqueNumbers = new HashSet<>(); 
     for (SudokuPosition inBlock : SudokuPosition.values()) { 
      firstBlockUniqueNumbers.add(sudoku[inBlock.x][inBlock.y]); 

      Set<Integer> samePosInOtherBlocksUniqueNumbers = new HashSet<>(); 
      for (SudokuPosition ofBlock : SudokuPosition.values()) { 
       int sameXinAll = inBlock.x + offset(ofBlock.x); 
       int sameYinAll = inBlock.y + offset(ofBlock.y); 
       samePosInOtherBlocksUniqueNumbers.add(sudoku[sameXinAll][sameYinAll]); 
      } 
      if (9 > samePosInOtherBlocksUniqueNumbers.size()) 
       // numbers where not unique at current block position 
       // through all the blocks 
       return false; 
     } 
     return 9 == firstBlockUniqueNumbers.size(); 
    } 

    private int offset(int xOrY) { 
     return xOrY * 3; 
    } 
} 

Я надеюсь, продемонстрировал полезность Переменные Java и насколько важны имена хороших идентификаторов.

Я думаю, что этот подход может быть улучшена 2-мя способами:

  • с использованием Java 8 Стрим API может заменить forech петли
  • имена элементов позиции как-то повторить их значения конструктора, которые могут привести к неприятные ошибки.Последнее может быть заменено каким-то умным расчетом на постоянное имя, которое доступно через name(), но для этой демонстрации оно может быть достаточно хорошим, так как оно ...