其思想就是 回溯法,相比n皇后问题只考虑行,数独问题同时考虑行和列进行定位。
n皇后问题博文: n皇后问题
解题思路
遍历行列,逐个位置定位,然后判断当前位置能放什么位置
关于子方格内9个数组不重复的判断,是行列偏移量+行/列增量
行列偏移量:3*(row/3)
行增量:i/3
列增量:i%3
通过递归实现回溯
JAVA实现
private static void printArr(char[][] arr) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
/**
* 判断当前位置(row,col)能否放置数字num
* @param board
* @param row
* @param col
* @param num
* @return
*/
public static boolean isValid(char[][] board,int row,int col,char num){
for (int i =0;i<9;i++){
//判断行
if(board[i][col]==num){
return false;
}
//判断列
if (board[row][i]==num){
return false;
}
//判断小方格里面
//3*(row/3)是行列的偏移量
//i/3是行的增量:0,0,0,1,1,1,2,2,2
//i%3是列的增量:0,1,2,0,1,2,0,1,2
if(board[3*(row/3)+i/3][3*(col/3)+i%3]==num){
return false;
}
}
//合法的插入位置
return true;
}
public static boolean helper(char[][] board){
for (int i=0;i<9;i++){
for (int j=0;j<9;j++){
if(board[i][j]=='.'){
for (char num='1';num<='9';num++){
if(isValid(board,i,j,num)){
board[i][j]=num;
//开始下一个位置的选择
//helper(board);
if(helper(board))
{
// System.out.println(i+" "+j);
return true;
}
//下一个情况全部遍历结束,没有合适的,则把当前位置 置.
board[i][j]='.';
}
}
//这里,说明当前的位置(i,j)没有合适的值插入,回溯到前一层的调用
return false;
}
}
}
printArr(board);
return true;
}
测试方法:
public static void main(String[] args) {
char[][] board = {
{ '5', '3', '.', '.', '7', '.', '.','.','.' },
{ '6', '.', '.', '1', '9', '5', '.','.','.' },
{ '.', '9', '8', '.', '.', '.', '.','6','.' },
{ '8', '.', '.','.' , '6','.' ,'.' ,'.','3'},
{ '4', '.', '.','8' , '.','3' ,'.' ,'.','1'},
{ '7', '.', '.','.' , '2','.' ,'.' ,'.','6'},
{ '.', '6', '.','.' , '.','.' ,'2' ,'8','.'},
{ '.', '.', '.','4' , '1','9' ,'.' ,'.','5'},
{ '.', '.', '.','.' , '8','.' ,'.' ,'7','9'}
};
System.out.println(helper(board));
}
需要注意的问题
我之前在回溯代码那一块写的是:
public static boolean helper(char[][] board){
for (int i=0;i<9;i++){
for (int j=0;j<9;j++){
if(board[i][j]=='.'){
for (char num='1';num<='9';num++){
if(isValid(board,i,j,num)){
board[i][j]=num;
//开始下一个位置的选择
helper(board);
// if(helper(board))
// {
// System.out.println(i+" "+j);
// return true;
// }
//下一个情况全部遍历结束,没有合适的,则把当前位置 置.
board[i][j]='.';
}
}
//这里,说明当前的位置(i,j)没有合适的值插入,回溯到前一层的调用
return false;
}
}
}
printArr(board);
return true;
}
结果:
原因:
递归调用栈,调用到printArr(board)打印最终的数组时,调用栈其实是压满了。。。。。打印数组后,调用了return true(只调用到了这一次true)。之后,helper(board)从最后的i=8,j=6 一个一个出栈
由于return false语句在return true之前,
所以最下面的一层(最外层的方法返回了false…)
修改:
if(helper(board))
{
//System.out.println(i+" "+j);
return true;
}
这样的话,最上层在执行了printArr(board);后返回true,if条件满足,返回true,栈一层一层都返回true。到最后最外层也返回true,满足题意。
运行结果