我想实现一项检查,看看数独在Java中是否有效,并且遇到了{http://leetcode.tgic.me/valid-sudoku/index.html)。
我理解它是如何验证行和列的,但是对于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网格中的每个单元格?我粗暴地强迫它并先尝试x=0, y=0
,offset=0
和offset=1
,但是offset=1
给了int ox = 1%3 = 1;
和int oy = 1/3
,所以{{1} },以及单元格board[0 + 1][0+(1/3)] = board[1][1/3]
代表什么等等?
答案 0 :(得分:1)
当你将n除以m时,两者都是int(文字或变量),结果也是int,所以1/3 - &gt; 0 因此,当 offset == 0 =&gt; ox = 0,oy = 0 offset == 1 =&gt; ox = 1,oy = 0 offset == 2 =&gt; ox = 2,oy = 0 offset == 3 - &gt; ox = 0,oy = 1 ... 因此,你将很好地循环3行和3列
答案 1 :(得分: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是一种面向对象的编程语言,我建议使用 objects 来确定坐标。我们可以将它们保存在一个数组中(设置一个书签,我通常会说“收集”而不是......)并用一个简单的forech循环迭代它...
此外,我们必须提前处理我们知道的固定数量的对象(每个有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枚举的有用性以及良好的标识符名称的重要性。
我认为这种方法可以通过两种方式得到改善:
name()
上可用的常量名称进行一些巧妙的计算来代替,但是对于这个演示,它可能已经足够好了...... 答案 2 :(得分:0)
我认为最理想的答案是:
public boolean isValidSudoku(char[][] board) {
if (board == null || board.length == 0) return false;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == '.') continue;
if (!isValid(board, i, j)) return false;
}
}
return true;
}
public boolean isValid(char[][] board, int row, int col) {
for (int i = 0; i < board.length; i++) {
if (i == row) continue;
if (board[i][col] == board[row][col]) return false;
}
for (int j = 0; j < board[0].length; j++) {
if (j == col) continue;
if (board[row][j] == board[row][col]) return false;
}
for (int i = (row / 3) * 3; i < (row / 3 + 1) * 3; i++) {
for (int j = (col / 3) * 3; j < (col / 3 + 1) * 3; j++) {
if (i == row && j == col) continue;
if (board[i][j] == board[row][col]) return false;
}
}
return true;
}