算法:
二维递归(递归时需要两层for循环)
一个for循环放行
另一个for循环放列
画树:
因为这个树形结构太大了,我抽取一部分,如图所示:
回溯三部曲:
1.确定函数参数和返回值
返回值:
boolean。因为只要解一个数独就可以返回了,不用一直搜取结果。
如果要把整棵树的所有结果都返回,才用void
参数:
char[][] board。题目自带的。
2.确定终止条件
本题递归不用终止条件
递归的下一层的棋盘一定比上一层的棋盘多一个数,等数填满了棋盘自然就终止(填满当然好了,说明找到结果了),所以不需要终止条件!
3.单层递归逻辑
for (int i = 0; i < 9; i++){ // 遍历行
for (int j = 0; j < 9; j++){ // 遍历列
if (board[i][j] != '.'){ // 跳过原始数字
continue;
}
for (char k = '1'; k <= '9'; k++){ // (i, j) 这个位置放k是否合适
if (isValidSudoku(i, j, k, board)){
board[i][j] = k;
if (solveSudokuHelper(board)){ // 如果找到合适一组立刻返回
return true;
}
board[i][j] = '.';//找不到就放"."
}
}
// 9个数都试完了,都不行,那么就返回false
return false;
// 因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解!
// 那么会直接返回, 「这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去!」
}
}
// 遍历完没有返回false,说明找到了合适棋盘位置了
return true;
}
判断棋盘是否合法
- 同行是否重复
for (int i = 0; i < 9; i++) { // 判断行里是否重复
if (board[row][i] == val) {
return false;
}
}
- 同列是否重复
for (int j = 0; j < 9; j++) { // 判断列里是否重复
if (board[j][col] == val) {
return false;
}
}
- 9宫格里是否重复
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
for (int j = startCol; j < startCol + 3; j++) {
if (board[i][j] == val ) {
return false;
}
}
}
return true;}
正确代码:
class Solution {
public void solveSudoku(char[][] board) {
backtracking(board);
}
boolean backtracking (char[][] board){
//二维递归
for (int row = 0; row < 9; row++){
for (int col = 0; col < 9; col++){
//若该位置有数字了,就跳出本层循环
if (board[row][col] != '.') continue;
//循环放置数字1-9
for (char k = '1'; k <= '9'; k++){
if (isValid(row, col, k, board)){
board[row][col] = k;
//如果找到合适一组立刻返回
if (backtracking(board)) return true;
}
board[row][col] = '.';
}
// 9个数都试完了,都不行,那么就返回false
// 因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解!
// 那么会直接返回, 「这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去!
return false;
}
}
return true;
}
boolean isValid(int row, int col, char var, char[][]board){
//先判错
//同行不重复
for (int i = 0; i <9; i++){
if (board[row][i] == var) return false;
}
//同列不重复
for (int i = 0; i <9; i++){
if (board[i][col] == var) return false;
}
//9宫格不重复
int startrow = (row/3)*3;
// `/` 表示整数除法。比如,row=0,startrow=0; row=3,startrow=3
int startcol = (col/3)*3;
for (int i= startrow; i < startrow+3; i++){
for (int j= startcol; j < startcol+3; j++){
if (board[i][j] == var) return false;
}
}
return true;
}
}
这道题好难,不太会写代码,边看正确答案边写的