Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could be partially filled, where empty cells are filled with the character '.'. Below is a partially filled sudoku which is valid.
Each column must have the numbers 1-9 occuring just once.
http://www.programcreek.com/2014/05/leetcode-valid-sudoku-java/
这道题让我们验证一个方阵是否为数独矩阵,判断标准是看各行各列是否有重复数字,以及每个小的3x3的小方阵里面是否有重复数字,如果都无重复,则当前矩阵是数独矩阵,但不代表待数独矩阵有解,只是单纯的判断当前未填完的矩阵是否是数独矩阵。那么根据数独矩阵的定义,我们在遍历每个数字的时候,就看看包含当前位置的行和列以及3x3小方阵中是否已经出现该数字,那么我们需要三个标志矩阵,分别记录各行,各列,各小方阵是否出现某个数字,其中行和列标志下标很好对应,就是小方阵的下标需要稍稍转换一下
X. https://leetcode.com/problems/valid-sudoku/discuss/15472/Short%2BSimple-Java-using-Strings
依次检查每行,每列,每个子九宫格是否出现重复元素,如果出现返回false,否则返回true.
难点在于表示第i个九宫格每个格点的坐标。
观察行号规律:
第0个九宫格:000111222; 第1个九宫格:000111222; 第2个九宫格:000111222;
第3个九宫格:333444555; 第4个九宫格:333444555; 第5个九宫格:333444555;
第6个九宫格:666777888; 第7个九宫格:666777888; 第8个九宫格:666777888;
可见对于每三个九宫格行号增3;对于单个九宫格,每三个格点行号增1。
因此第i个九宫格的第j个格点的行号可表示为i/3*3+j/3(每个小九宫格j都是从0~9递增)
观察列号规律:
第0个九宫格:012012012; 第1个九宫格:345345345; 第2个九宫格:678678678;
第3个九宫格:012012012; 第4个九宫格:345345345; 第5个九宫格:678678678;
第6个九宫格:012012012; 第7个九宫格:345345345; 第8个九宫格:678678678;
可见对于下个九宫格列号增3,循环周期为3;对于单个九宫格,每个格点行号增1,周期也为3。
周期的数学表示就是取模运算mod。
因此第i个九宫格的第j个格点的列号可表示为i%3*3+j%3(每个小九宫格j都是从0~9递增)
部分填充的有效数独,不需要填充
细节分析题
(1)检查行
(2)检查列
(3)检查9个子宫格
https://leetcode.com/discuss/17990/sharing-my-easy-understand-java-solution-using-set
https://leetcode.com/discuss/27272/shared-my-concise-java-code
for(int i = 0; i<9; i++){
HashSet<Character> rows = new HashSet<Character>();
HashSet<Character> columns = new HashSet<Character>();
HashSet<Character> cube = new HashSet<Character>();
for (int j = 0; j < 9;j++){
if(board[i][j]!='.' && !rows.add(board[i][j]))
return false;
if(board[j][i]!='.' && !columns.add(board[j][i]))
return false;
int RowIndex = 3*(i/3);
int ColIndex = 3*(i%3);
if(board[RowIndex + j/3][ColIndex + j%3]!='.' && !cube.add(board[RowIndex + j/3][ColIndex + j%3]))
return false;
}
}
return true;
}
https://leetcode.com/discuss/64668/short-simple-java-using-strings
Set seen = new HashSet();
for (int i=0; i<9; ++i) {
for (int j=0; j<9; ++j) {
if (board[i][j] != '.') {
String b = "(" + board[i][j] + ")";
if (!seen.add(b + i) || !seen.add(j + b) || !seen.add(i/3 + b + j/3))
return false;
}
}
}
return true;
}
Just occurred to me that we can also make it really clear and self-explaining
public boolean isValidSudoku(char[][] board) {
Set seen = new HashSet();
for (int i=0; i<9; ++i) {
for (int j=0; j<9; ++j) {
char number = board[i][j];
if (number != '.')
if (!seen.add(number + " in row " + i) ||
!seen.add(number + " in column " + j) ||
!seen.add(number + " in block " + i/3 + "-" + j/3))
return false;
}
}
return true;
}
http://www.fusu.us/2013/07/verifying-sudoku-solution.html
http://www.cnblogs.com/TenosDoIt/p/3800485.html
http://stackoverflow.com/questions/5111434/sudoku-validity-check-algorithm-how-does-this-code-works
Read full article from LeetCode - Valid Sudoku | Darren's Blog
Each row must have the numbers 1-9 occuring just once.
| |
And the numbers 1-9 must occur just once in each of the 9 sub-boxes of the grid.
- With three passes
public boolean isValidSudoku(char[][] board) {
HashSet<Character> set = new HashSet<Character>();
// Check for each row
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == '.')
continue;
if (set.contains(board[i][j]))
return false;
set.add(board[i][j]);
}
set.clear();
}
// Check for each column
for (int j = 0; j < 9; j++) {
for (int i = 0; i < 9; i++) {
if (board[i][j] == '.')
continue;
if (set.contains(board[i][j]))
return false;
set.add(board[i][j]);
}
set.clear();
}
// Check for each sub-grid
for (int k = 0; k < 9; k++) {
for (int i = k/3*3; i < k/3*3+3; i++) {
for (int j = (k%3)*3; j < (k%3)*3+3; j++) {
if (board[i][j] == '.')
continue;
if (set.contains(board[i][j]))
return false;
set.add(board[i][j]);
}
}
set.clear();
}
return true;
}
X. https://www.programcreek.com/2014/05/leetcode-valid-sudoku-java/public boolean isValidSudoku(char[][] board) { if (board == null || board.length != 9 || board[0].length != 9) return false; // check each column for (int i = 0; i < 9; i++) { boolean[] m = new boolean[9]; for (int j = 0; j < 9; j++) { if (board[i][j] != '.') { if (m[(int) (board[i][j] - '1')]) { return false; } m[(int) (board[i][j] - '1')] = true; } } } //check each row for (int j = 0; j < 9; j++) { boolean[] m = new boolean[9]; for (int i = 0; i < 9; i++) { if (board[i][j] != '.') { if (m[(int) (board[i][j] - '1')]) { return false; } m[(int) (board[i][j] - '1')] = true; } } } //check each 3*3 matrix for (int block = 0; block < 9; block++) { boolean[] m = new boolean[9]; for (int i = block / 3 * 3; i < block / 3 * 3 + 3; i++) { for (int j = block % 3 * 3; j < block % 3 * 3 + 3; j++) { if (board[i][j] != '.') { if (m[(int) (board[i][j] - '1')]) { return false; } m[(int) (board[i][j] - '1')] = true; } } } } return true; }Code from http://xixiaogualu.blogspot.com/2013/09/leetcode-valid-sudoku.html
http://www.programcreek.com/2014/05/leetcode-valid-sudoku-java/
It used boolean[10], instead of set:boolean[] checker=new boolean[10];checker[c-'0']=true;EPI Solution:
- With one pass: space for speed
public boolean isValidSudoku(char[][] board) {
// rowChecker[i][j]=true: j appears in row i
boolean[][] rowChecker = new boolean[9][9];
// columnChecker[i][j]=true: j appears in column i
boolean[][] columnChecker = new boolean[9][9];
// gridChecker[i][j]=true: j appears in grid i
// numberring from left to right, then top to bottom
boolean[][] gridChecker = new boolean[9][9];
// One-pass scan in row-major manner
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == '.')
continue;
int val = board[i][j] - '1';
// Check for the corresponding row, column, and grid at the same time
if (rowChecker[i][val] || columnChecker[j][val] || gridChecker[i/3*3+j/3][val])
return false;
rowChecker[i][val] = columnChecker[j][val] = gridChecker[i/3*3+j/3][val] = true;
}
}
return true;
}
https://www.cnblogs.com/grandyang/p/4421217.html这道题让我们验证一个方阵是否为数独矩阵,判断标准是看各行各列是否有重复数字,以及每个小的3x3的小方阵里面是否有重复数字,如果都无重复,则当前矩阵是数独矩阵,但不代表待数独矩阵有解,只是单纯的判断当前未填完的矩阵是否是数独矩阵。那么根据数独矩阵的定义,我们在遍历每个数字的时候,就看看包含当前位置的行和列以及3x3小方阵中是否已经出现该数字,那么我们需要三个标志矩阵,分别记录各行,各列,各小方阵是否出现某个数字,其中行和列标志下标很好对应,就是小方阵的下标需要稍稍转换一下
X. https://leetcode.com/problems/valid-sudoku/discuss/15472/Short%2BSimple-Java-using-Strings
public boolean isValidSudoku(char[][] board) {
Set seen = new HashSet();
for (int i=0; i<9; ++i) {
for (int j=0; j<9; ++j) {
char number = board[i][j];
if (number != '.')
if (!seen.add(number + " in row " + i) ||
!seen.add(number + " in column " + j) ||
!seen.add(number + " in block " + i/3 + "-" + j/3))
return false;
}
}
return true;
}
X. https://blog.csdn.net/mine_song/article/details/70207326依次检查每行,每列,每个子九宫格是否出现重复元素,如果出现返回false,否则返回true.
难点在于表示第i个九宫格每个格点的坐标。
观察行号规律:
第0个九宫格:000111222; 第1个九宫格:000111222; 第2个九宫格:000111222;
第3个九宫格:333444555; 第4个九宫格:333444555; 第5个九宫格:333444555;
第6个九宫格:666777888; 第7个九宫格:666777888; 第8个九宫格:666777888;
可见对于每三个九宫格行号增3;对于单个九宫格,每三个格点行号增1。
因此第i个九宫格的第j个格点的行号可表示为i/3*3+j/3(每个小九宫格j都是从0~9递增)
观察列号规律:
第0个九宫格:012012012; 第1个九宫格:345345345; 第2个九宫格:678678678;
第3个九宫格:012012012; 第4个九宫格:345345345; 第5个九宫格:678678678;
第6个九宫格:012012012; 第7个九宫格:345345345; 第8个九宫格:678678678;
可见对于下个九宫格列号增3,循环周期为3;对于单个九宫格,每个格点行号增1,周期也为3。
周期的数学表示就是取模运算mod。
因此第i个九宫格的第j个格点的列号可表示为i%3*3+j%3(每个小九宫格j都是从0~9递增)
部分填充的有效数独,不需要填充
细节分析题
(1)检查行
(2)检查列
(3)检查9个子宫格
public boolean isValidSudoku(char[][] board) {
for (int i = 0; i < 9; i++) {
HashSet<Character> row = new HashSet<>();
HashSet<Character> column = new HashSet<>();
HashSet<Character> cube = new HashSet<>();
for (int j = 0; j < 9; j++) {
// 检查第i行,在横坐标位置
if (board[i][j] != '.' && !row.add(board[i][j]))
return false;
// 检查第i列,在纵坐标位置
if (board[j][i] != '.' && !column.add(board[j][i]))
return false;
// 行号+偏移量
int RowIndex = 3 * (i / 3) + j / 3;
// 列号+偏移量
int ColIndex = 3 * (i % 3) + j % 3;
// 每个小九宫格,总共9个
if (board[RowIndex][ColIndex] != '.' && !cube.add(board[RowIndex][ColIndex]))
return false;
}
}
return true;
}
https://leetcode.com/discuss/17990/sharing-my-easy-understand-java-solution-using-set
https://leetcode.com/discuss/27272/shared-my-concise-java-code
Just trying to explain how to think about
%
and /
. These two operators can be helpful for matrix traversal problems.
For a block traversal, it goes the following way.
0,0
, 0,1
, 0,2
; < --- 3 Horizontal Steps followed by 1 Vertical step to next level.1,0
, 1,1
, 1,2
; < --- 3 Horizontal Steps followed by 1 Vertical step to next level.2,0
, 2,1
, 2,2
; < --- 3 Horizontal Steps.
And so on... But, the
j
iterates from 0 to 9
.
But we need to stop after 3 horizontal steps, and go down 1 step vertical.
Use
%
for horizontal traversal. Because %
increments by 1 for each j : 0%3 = 0 , 1%3 = 1, 2%3 = 2
, and resets back. So this covers horizontal traversal for each block by 3 steps.
Use
/
for vertical traversal. Because /
increments by 1 after every 3 j: 0/3 = 0; 1/3 = 0; 2/3 =0; 3/3 = 1
.
So far, for a given block, you can traverse the whole block using just j.
But because j is just 0 to 9, it will stay only first block. But to increment block, use i. To movehorizontally to next block, use
%
again : ColIndex = 3 * i%3
(Multiply by 3 so that the next block is after 3 columns. Ie 0,0
is start of first block, second block is 0,3
(not 0,1
);
Similarly, to move to next block vertically, use
public boolean isValidSudoku(char[][] board) {/
and multiply by 3 as explained above. Hope this helps.for(int i = 0; i<9; i++){
HashSet<Character> rows = new HashSet<Character>();
HashSet<Character> columns = new HashSet<Character>();
HashSet<Character> cube = new HashSet<Character>();
for (int j = 0; j < 9;j++){
if(board[i][j]!='.' && !rows.add(board[i][j]))
return false;
if(board[j][i]!='.' && !columns.add(board[j][i]))
return false;
int RowIndex = 3*(i/3);
int ColIndex = 3*(i%3);
if(board[RowIndex + j/3][ColIndex + j%3]!='.' && !cube.add(board[RowIndex + j/3][ColIndex + j%3]))
return false;
}
}
return true;
}
https://leetcode.com/discuss/64668/short-simple-java-using-strings
Collect the set of things we see, encoded as strings. For example:
'4' in row 7
is encoded as"(4)7"
.'4' in column 7
is encoded as"7(4)"
.'4' in the top-right block
is encoded as"0(4)2"
.
Scream
public boolean isValidSudoku(char[][] board) {false
if we ever fail to add something because it was already added (i.e., seen before).Set seen = new HashSet();
for (int i=0; i<9; ++i) {
for (int j=0; j<9; ++j) {
if (board[i][j] != '.') {
String b = "(" + board[i][j] + ")";
if (!seen.add(b + i) || !seen.add(j + b) || !seen.add(i/3 + b + j/3))
return false;
}
}
}
return true;
}
Just occurred to me that we can also make it really clear and self-explaining
public boolean isValidSudoku(char[][] board) {
Set seen = new HashSet();
for (int i=0; i<9; ++i) {
for (int j=0; j<9; ++j) {
char number = board[i][j];
if (number != '.')
if (!seen.add(number + " in row " + i) ||
!seen.add(number + " in column " + j) ||
!seen.add(number + " in block " + i/3 + "-" + j/3))
return false;
}
}
return true;
}
http://www.fusu.us/2013/07/verifying-sudoku-solution.html
public static boolean isValidSudoku(int[][] board, int order) { | |
long[] rows = new long[order * order]; | |
long[] columns = new long[order * order]; | |
long[][] boxes = new long[order][order]; | |
int length = order * order; | |
for (int i = 0; i < length; i++) { | |
int boxI = i / 3; | |
for (int j = 0; j < length; j++) { | |
int boxJ = j / 3; | |
int value = board[i][j]; | |
// consider unfinished solutions | |
if (value == 0) { | |
continue; | |
} | |
if ((rows[i] & 1 << (value - 1)) > 0) { | |
return false; | |
} else { | |
rows[i] = rows[i] | 1 << (value - 1); | |
} | |
if ((columns[i] & 1 << (value - 1)) > 0) { | |
return false; | |
} else { | |
columns[i] = columns[i] | 1 << (value - 1); | |
} | |
if ((boxes[boxI][boxJ] & 1 << (value - 1)) > 0) { | |
return false; | |
} else { | |
boxes[boxI][boxJ] = | |
boxes[boxI][boxJ] | 1 << (value - 1); | |
} | |
} | |
} | |
return true; | |
} |
bool
isValidSudoku(vector<vector<
char
> > &board) {
int
rowValid[10] = {0};
//用于判断某一行是否合法,对于行来说这个数组可以重复使用
int
columnValid[9][10] = {0};
//用于判断某一列是否合法
int
subBoardValid[9][10] = {0};
//用于判断某一个九宫格是否合法
for
(
int
i = 0; i < 9; i++)
{
memset
(rowValid, 0,
sizeof
(rowValid));
for
(
int
j = 0; j < 9; j++)
if
(board[i][j] !=
'.'
)
{
if
(!checkValid(rowValid, board[i][j]-
'0'
) ||
!checkValid(columnValid[j], board[i][j]-
'0'
) ||
!checkValid(subBoardValid[i/3*3+j/3], board[i][j]-
'0'
))
return
false
;
}
}
return
true
;
}
bool
checkValid(
int
vec[],
int
val)
{
if
(vec[val] == 1)
return
false
;
vec[val] = 1;
return
true
;
}
上面的算法中,在双重循环时,我们默认了第一重循环表示矩阵的行、第二重循环表示矩阵的列。可以换一种思路:
- 在检测行是否合法时,i 表示矩阵的行,j 表示矩阵的列;
- 检测列是否合法时,i 表示矩阵的列,j 表示矩阵的行;
- 检测九宫格是否合法时,i 表示九宫格的标号,j 表示九宫格里的每个元素(只是我们需要根据i、j定位相应的元素到原来的矩阵:第 i 个九宫格里面的第 j 个元素在原矩阵的第 3*(i/3) + j/3 行,第 3*(i%3) + j%3)列,“/” 表示整数除法)
bool
isValidSudoku(vector<vector<
char
> > &board) {
int
rowValid[10] = {0};
//用于判断某一行是否合法
int
columnValid[10] = {0};
//用于判断某一列是否合法
int
subBoardValid[10] = {0};
//用于判断某一个九宫格是否合法
for
(
int
i = 0; i < 9; i++)
{
memset
(rowValid, 0,
sizeof
(rowValid));
memset
(columnValid, 0,
sizeof
(columnValid));
memset
(subBoardValid, 0,
sizeof
(subBoardValid));
for
(
int
j = 0; j < 9; j++)
{
if
(!checkValid(rowValid, board[i][j]-
'0'
) ||
!checkValid(columnValid, board[j][i]-
'0'
) ||
!checkValid(subBoardValid, board[3*(i/3) + j/3][3*(i%3) + j%3]-
'0'
))
return
false
;
}
}
return
true
;
}
http://stackoverflow.com/questions/5111434/sudoku-validity-check-algorithm-how-does-this-code-works
public static bool IsValid(int[] values)
{
// bit field (set to zero => no values processed yet)
int flag = 0;
foreach (int value in values)
{
// value == 0 => reserved for still not filled cells, not to be processed
if (value != 0)
{
// prepares the bit mask left-shifting 1 of value positions
int bit = 1 << value;
// checks if the bit is already set, and if so the Sudoku is invalid
if ((flag & bit) != 0)
return false;
// otherwise sets the bit ("value seen")
flag |= bit;
}
}
// if we didn't exit before, there are no problems with the given values
return true;
}
http://tech-wonderland.net/blog/leetcode-valid-sudoku.htmlRead full article from LeetCode - Valid Sudoku | Darren's Blog