题目地址:
https://www.lintcode.com/problem/sudoku-solver/description
解数独。
直接用DFS+回溯求解即可。代码如下:
import java.util.ArrayList;
import java.util.List;
public class Solution {
/**
* @param board: the sudoku puzzle
* @return: nothing
*/
public void solveSudoku(int[][] board) {
// write your code here
dfs(board, 0);
}
// 从start开始填数,如果填成功了则返回true
private boolean dfs(int[][] board, int start) {
int n = board.length;
// 走到下一个需要填数的地方
while (start < n * n && board[start / n][start % n] != 0) {
start++;
}
// 如果走到末尾了,说明全填完了,返回true
if (start == n * n) {
return true;
}
// 求一下要填数的位置的坐标
int x = start / n, y = start % n;
// validNums求的是在board[x][y]这个地方允许填的数字
for (int num : validNums(board, x, y)) {
// 尝试填
board[x][y] = num;
// 如果填写成功,返回true
if (dfs(board, start + 1)) {
return true;
}
// 如果没成功,则恢复现场填下一个数
board[x][y] = 0;
}
return false;
}
private List<Integer> validNums(int[][] board, int x, int y) {
List<Integer> res = new ArrayList<>();
for (int n = 1; n <= 9; n++) {
boolean valid = true;
for (int i = 0; i < board.length; i++) {
if (i != y && board[x][i] == n) {
valid = false;
break;
}
if (i != x && board[i][y] == n) {
valid = false;
break;
}
}
if (!valid) {
continue;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int c1 = x / 3 * 3, c2 = y / 3 * 3;
if (c1 + i != x && c2 + j != y && board[c1 + i][c2 + j] == n) {
valid = false;
break;
}
}
if (!valid) {
break;
}
}
if (valid) {
res.add(n);
}
}
return res;
}
}
时间复杂度 ,空间 , 为矩阵规模。
注意,回溯的时候一定要记得恢复现场,否则尝试下一个数字的时候会受到本不该填但已经填了的数的影响。