问题描述
问题分析
- 验证给定 9*9 二维数组是否符合以下性质:
- 同一行不包含重复元素
- 同一列不包含重复元素
- 同一 3 * 3 子方块不包含重复元素
- 验证重复问题,可以用 HashSet,也可以用数组,相应字符码值作为数组索引。
- 但该题的难点在于,如何只用一个双层循环,便对三个性质全部验证完毕。
- 对于一行,很容易转为一列
- 那么对于一行,如何映射为一个子方块呢?
- 对于一行,如何映射为一个子方块呢?
首先,如果给你一个m*n
的矩阵,若将它转为一个一维数组,那么m[i][j]
在数组中的索引便是i * n + j
,反过来,若将一个一维数组映射为一个m*n
的矩阵,那么对于arr[pos]
元素,到矩阵中便是m[pos/n][pos % n]
所以,如果我们现在若将原二维数组中的第一行映射成一个3*3
矩阵的话,那么m[0][j]
便映射成了sub[j/n][j%n]
。
但其他行呢,同样是找规律,对于第 i 行,它所映射的子方块的左上角坐标为:
第i行 | 子方块的左上角坐标 |
---|---|
0 | [0,0] |
1 | [0,3] |
2 | [0,6] |
3 | [3,0] |
4 | [3,3] |
5 | [3,6] |
6 | [6,0] |
7 | [6,3] |
8 | [6,6] |
所以,i 行在第0行的基础上要加一个offset,偏移量为[i/3 *3, i%3 * 3]
所以最终的第i行m[i][j]
映射的子方块坐标为 sub[i/3 *3 + j/3, i%3 * 3 + j % 3]
经验教训
- 如何映射?
代码实现
- HashSet
public boolean isValidSudoku(char[][] board) {
if (board == null || board.length == 0 || board[0] == null || board[0].length == 0) {
return false;
}
for (int i = 0; i < 9; ++i) {
//存储当前i行已遍历元素
HashSet<Character> row = new HashSet<Character>();
//存储当前i列已遍历元素
HashSet<Character> col = new HashSet<Character>();
//存储i行所有元素映射成的子方格已遍历对应的元素
HashSet<Character> subBox = new HashSet<Character>();
for (int j = 0; j < 9; ++j) {
if (board[i][j] != '.' && ! row.add(board[i][j])) {
return false;
}
if (board[j][i] != '.' && ! col.add(board[j][i])) {
return false;
}
//将第i行元素映射成子方格元素的坐标
int subBoxX = (i / 3) * 3 + j / 3;
int subBoxY = (i % 3) * 3 + j % 3;
if (board[subBoxX][subBoxY] != '.' && ! subBox.add(board[subBoxX][subBoxY])) {
return false;
}
}
}
return true;
}
- 数组
public boolean isValidSudoku(char[][] board) {
if (board == null || board.length == 0 || board[0] == null || board[0].length == 0) {
return false;
}
for (int i = 0; i < 9; ++i) {
boolean[] row = new boolean[10];
boolean[] col = new boolean[10];
boolean[] subBox = new boolean[10];
for (int j = 0; j < 9; ++j) {
if (board[i][j] != '.') {
if (row[board[i][j] - '0']) {
return false;
}else {
row[board[i][j] - '0'] = true;
}
}
if (board[j][i] != '.') {
if (col[board[j][i] - '0']) {
return false;
}else {
col[board[j][i] - '0'] = true;
}
}
int subBoxX = (i / 3) * 3 + j / 3;
int subBoxY = (i % 3) * 3 + j % 3;
if (board[subBoxX][subBoxY] != '.') {
if (subBox[board[subBoxX][subBoxY] - '0']) {
return false;
}else {
subBox[board[subBoxX][subBoxY] - '0'] = true;
}
}
}
}
return true;
}