sudoku solver(数独)

Write a program to solve a Sudoku puzzle by filling the empty cells.

Empty cells are indicated by the character '.'.

You may assume that there will be only one unique solution.

A sudoku puzzle...

1 每个backtracking的题目,最好都有独立判断isValid的程序,这样架构清楚。同时,valid判断函数在这里可以稍微研究一下。只要当前要判断的位置上的数值和本行没有重复,本列没有重复,九宫格没有重复就可以。一旦重复立即返回,减少判断次数。

2 backtracking的递归函数,怎么能没有返回值呢?!因为要判断递归的方案正确与否,所以这里的递归一定是有返回值的(除非是combination那种没有正确错误概念的backtracking)!

3 可以考虑“先放置,再判断”的方案。比如这里,首先判断当前位置是否为空,如果为空,那么放置一个元素,检查它是否正确。如果正确,就继续进行下面的递归(也就是第29行 isValid&&solveSudoku的作用)。当函数返回错误之后,将刚刚的数值变为空,再进行下一次尝试即可。

5 最后一点需要注意的是,当i,j循环完毕之后,表明已经解出了sudoku,需要返回!切记切记,最终情况!

简单地说思路就是循环处理子问题,对于每个格子,带入不同的9个数,然后判合法,如果成立就递归继续,结束后把数字设回空。大家可以看出代码结构和N-Queens是完全一样的。判合法其实在这里因为每次进入时已经保证之前的board不会冲突,所以不需要判断整个盘,只需要看当前加入的数字和之前是否冲突就可以,这样可以大大提高运行效率,毕竟判合法在程序中被多次调用。

class Solution {
    public void solveSudoku(char[][] board) {
        helper(board,0,0);
    }
    //判断row,col位置是否为'.',是的话就设置值。
    //因为要判断是否正确,所以需要返回值
    public boolean helper(char[][] board,int row,int col){
        if(col>=9){  //下一个位置超出列,就是进行下一行
           return helper(board,row+1,0);
        }
        if(row==9){
            return true;
        }
        //如果该位置是'.',则要添加数字
        if(board[row][col]=='.'){
            //依次给该位置添加1-9
            for(int k=1;k<=9;k++){
                board[row][col]=(char)(k+'0');
                if(isValid(board,row,col)){//如果有效,就进行下一个位置添加
                    if(helper(board,row,col+1))//如果后面的添加返回true,表明添加成功,返回true,否则就尝试下一个k
                        return true;
                }
                board[row][col]='.';
            }
        }else{
           return helper(board,row,col+1);
        }
        return false;
    }
    /*
    前面都已经判断了,只要判断该位置添加数字后是否符合要求,也就是看该行、列有没有和该元素相同的,而且该位置所在的九宫格中也不能有和它相同的
    */
    public boolean isValid(char[][] board,int row,int col){
        //判断列是否有相同的,再同列不同行,元素却相同
        for(int i=0;i<9;i++){
            if(i!=row&&board[i][col]==board[row][col]) 
                return false;
        }
        //判断行是否有相同的,同行不同列
        for(int j=0;j<9;j++){
            if(j!=col&&board[row][col]==board[row][j])
                return false;
        }
        
        //判断该位置所在九宫格是否有相同的
        /*要根据该位置找到所在九宫格的行和列的范围
        每个九宫格的行的范围是0-2,3-5,6-8,
        */
        for(int i=row/3*3;i<row/3*3+3;i++)
        {
            for(int j=col/3*3;j<col/3*3+3;j++){
                if((i!=row||j!=col)&&board[i][j]==board[row][col])
                    return false;
            }
        }
        
        return true;
    }
}
原文地址:https://www.cnblogs.com/xiaolovewei/p/8320182.html