解数独回溯算法详解(leetCode 37)(困难)

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sudoku-solver

这篇文章主要讲解下leetCode官方的回溯解法

class Solution {
    //line二维数组主要保存某一行是否存在数字,其中[i][j],i表示那一行,j表示该行存在的数字
    private boolean[][] line=new boolean[9][9];
    //column二维数组主要保存某一列是否存在数字,其中[i][j],i表示那一列,j表示该列存在的数字
    private boolean[][] column=new boolean[9][9];
    //block三维数组主要保存某一小块是否存在数字,其中[i][j][digit],[i][j]表示数字board中的位                
    //置,digit表示该位置上的数字
    private boolean[][][] block=new boolean[3][3][9];
    //标志号,表示该位置是否已经存在
    private boolean valid=false;
    //保存board数组中空白位置的下标
    private List<int[]> spaces=new ArrayList<int[]>();

    public void solveSudoku(char[][] board) {
        //遍历board数组,主要是初始化line,column,block,spaces数组
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                //board[i][j]位置为空,将该位置的下标保存在spaces中
                if(board[i][j]=='.'){
                    spaces.add(new int[]{i,j});
                //如果不为空,即存在数字,将line,column,block数组的对应位置置为true
                }else{
                    //这里的原因为数组下标范围为0-8,而board 数组中数字范围为1-9
                    int digit=board[i][j]-'0'-1;
                    line[i][digit]=column[j][digit]=block[i/3][j/3][digit]=true;
                }
            }
        }
        //回溯,从spaces数组的0号下标开始
        dfs(board,0);
    }
    private void dfs(char[][] board,int index){
        //终止条件为遍历完了所有的spaces元素
        if(index==spaces.size()){
            //将标志位设置为true
            valid=true;
            return;
        }
        
        //获取spaces下标,即board数组中[i][j]位置,此时这个位置为空
        int[] space=spaces.get(index);
        int i=space[0];
        int j=space[1];
        //遍历,将0-9的数字都填一遍
        for(int digit=0;digit<9&&!valid;digit++){
            //如果填入的数字满足要求,即行列以及3*3块都不存在该数字,即digit
            if(!line[i][digit]&&!column[j][digit]&&!block[i/3][j/3][digit]){
                //将line,column,block数组的对应位置置为true,表明该位置已经填入数字
                line[i][digit]=column[j][digit]=block[i/3][j/3][digit]=true;
                //将board数组对应位置填入相应的数字,将int类型转换为char类型
                board[i][j]=(char)(digit+'0'+1);
                //加入数字后,继续调用dfs()函数,进行回溯
                dfs(board,index+1);
                //将对应的标志为置为false,方便加入下一个数字,这里没有将board[i][j]恢复为原    
                //样,是因为下一个数字可以将其直接覆盖,所以可以不恢复该board数组
                line[i][digit]=column[j][digit]=block[i/3][j/3][digit]=false;
            }
        }
    }
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值