1. 方法一
**class Solution {
boolean[][] usedRow;
boolean[][] usedCol;
boolean[][] usedBoxed;
public Solution() {
this.usedRow = new boolean[10][10];
this.usedCol = new boolean[10][10];
this.usedBoxed = new boolean[10][10];
}
public void solveSudoku(char[][] board) {
initSudo(board);
dfs(board, 0, 0);
}
private void initSudo(char[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
int num = board[i][j] - '0';
if (num > 0 && num <= 9) {
usedRow[i][num] = true;
usedCol[j][num] = true;
usedBoxed[(i / 3) * 3 + j / 3][num] = true;
}
}
}
}
private boolean dfs(char[][] board, int i, int j) {
if (j == board[0].length) {
j = 0;
i++;
if (i == board.length) {
return true;
}
}
if (board[i][j] == '.') {
for (int k = 1; k <= 9; k++) {
if (!usedRow[i][k] && !usedCol[j][k] && !usedBoxed[(i / 3) * 3 + j / 3][k]) {
usedRow[i][k] = true;
usedCol[j][k] = true;
usedBoxed[(i / 3) * 3 + j / 3][k] = true;
board[i][j] = (char) (k + '0');
if (dfs(board, i, j + 1)) {
return true;
}
usedRow[i][k] = false;
usedCol[j][k] = false;
usedBoxed[(i / 3) * 3 + j / 3][k] = false;
board[i][j] = '.';
}
}
} else {
// 此处加与不加return的区别?
// 如果加了,比如说之前第一个是数字,说明填过了,已经组成一张完整的棋盘
// 如果不加,必然会遍历到最后一个格子,之前的没有联系到一起,即不是一张完整棋盘。
return dfs(board, i, j + 1);
}
return false;
}
}**
注意点
回溯法的返回值问题
- 如果 需要找到某些解的时候,必然是带有返回值的。
- 注意else分支。在写的时候,经常会把else分支给忽略了。如果忽略了,就会枚举不全。
方法二
public void solveSudoku(char[][] board) {
backTracking(board);
}
private boolean backTracking(char[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == '.') {
for (char k = '1'; k <= '9'; k++) {
if (validateNum(k, i, j, board)) {
board[i][j] = k;
if (backTracking(board)) {
return true;
}
board[i][j] = '.';
}
}
return false;
}
}
}
return true;
}
private boolean validateNum(int value, int row, int col, char[][] board) {
for (int i = 0; i < 9; i++) {
if (board[i][col] == value) {
return false;
}
}
for (int i = 0; i < 9; i++) {
if (board[row][i] == value) {
return false;
}
}
int rowIndex = (row / 3) * 3;
int colIndex = (col / 3) * 3;
for (int i = rowIndex; i < rowIndex + 3; i++) {
for (int j = colIndex; j < colIndex + 3; j++) {
if (board[i][j] == value) {
return false;
}
}
}
return true;
}
问题 为什么第一种方法,必须加上else,第二种方法不需要呢?区别在哪里?
第一种方法是逐行填的。 private boolean dfs(char[][] board, int i, int j)
第二种方法是尝试所有可能的数字。 private boolean backTracking(char[][] board)。
如果判断的对象是带有Index,逐个数字填的。需要考虑各种情况 。如果函数的对象是整整体,则不需要再次判断。
第一种方法是逐行。第2种方法相当于每次暴力搜索全部。因此不用单独判断每一行的状态。