Leetcode——解数独

题目描述

在这里插入图片描述
在这里插入图片描述

题目分析

建议食用本题前先看看36.有效的数独,解数独也使用到该题里面如何判断重复的思路。

  • 本题用到的是回溯的思路,所谓回溯,其实就是在进行一步操作之后,违反了规则,而进行情景恢复的步骤,换句话说,回溯就是把你刚做的操作撤销,回到操作之前的样子,类似于Ctrl+Z。我们通过回溯的方法,对每一个格子填入1-9进行尝试,如果成功就进行下一步,失败即进行回溯,回到上一步。
  • 要填入一个数,需要判断行、列和九宫格内是否有重复数字出现。我们可以使用三个二维数组来实现,例如rows[3][7]的值为1,就说明第三行中,7这个数已经出现了一次,如果要插入的时候,发现已经为1,则破坏了规则。

题目解答

class Solution {
    
    
    //box大小
    int n=3;
    //数独大小
    int N=n*n;
    //保存行、列和3*3方格中的数
    int[][] rows=new int[N][N+1];
    int[][] columns=new int[N][N+1];
    int[][] boxes=new int[N][N+1];

    char[][] board;

    //标记该行是否已完成
    boolean sudokuSolved=false;

    public void solveSudoku(char[][] board) {
    
    
        this.board=board;

        //初始化rows,columns和boxes
        for(int i=0;i<N;i++){
    
    
            for(int j=0;j<N;j++){
    
    
                int num=board[i][j];
                if(num!='.'){
    
    
                    int d=Character.getNumericValue(num);
                    placeNumber(d,i,j);
                }
            }
        }
        //开始方法
        backtrack(0,0);
    }
    /**
    *把数字放进rows、columns和boxes里面
    */
    public void placeNumber(int d,int row,int col){
    
    
        int idx=(row/n)*n+col/n;
        //某行和某列的d位置+1,当d位置为2时,则重复
        rows[row][d]++;
        columns[col][d]++;
        boxes[idx][d]++;
        board[row][col]=(char)(d+'0');
    }
    //回溯法
    public void backtrack(int row,int col){
    
    
        if(board[row][col]=='.'){
    
    
            for(int d=1;d<10;d++){
    
    
                if(couldPlace(d,row,col)){
    
    
                    placeNumber(d,row,col);
                    placeNextNumber(row,col);
                    //如果还没有找到解,就进行回溯
                    if(!sudokuSolved) removeNumber(d,row,col);
                }
            }
        }
        else placeNextNumber(row,col);
    }
    //判断是否能放进格子
    public boolean couldPlace(int d,int row,int col){
    
    
        int idx=(row/n)*n+col/n;
        return rows[row][d]+columns[col][d]+boxes[idx][d]==0;
    }
    //放入下个数字
    public void placeNextNumber(int row,int col){
    
    
        //如果到达边界的时候,说明已经找到解
        if((col==N-1)&&(row==N-1)){
    
    
            sudokuSolved=true;
        }else{
    
    
            //如果列是最后,就进入下一行
            if(col==N-1) backtrack(row+1,0);
            //否则就进入同行的下一个
            else backtrack(row,col+1);
        }
    }
    //回溯,删除数字
    public void removeNumber(int d,int row,int col){
    
    
        int idx=(row/n)*n+col/n;
        rows[row][d]--;
        columns[col][d]--;
        boxes[idx][d]--;
        board[row][col]='.';
    }
}

猜你喜欢

转载自blog.csdn.net/fucccck_ly/article/details/105513873