0
点赞
收藏
分享

微信扫一扫

78、★★双层嵌套-两层for循环的回溯-LeetCode-37.解数独

心智的年轮 2022-04-16 阅读 39

题目描述

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

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

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

思路

1)代码随想录:时间复杂度高

学到的内容:字符的遍历循环:第一次用到!

for(char k = '1';k <= '9';k++)

这个想法,确实第一次想不到!

实际每一个backTrack中只修改了一个 '.',有多少个点就需要传入多少次!每次都是传入一个少了一个点的新二维数组!

如果走到最后 ' . '改完了,就在最后一层的多层for循环中返回,一层一层返回true,就结束了该方法!如果遇到了false;返回上一层继续改!

就是这块儿回溯的思路一开始没想清楚

其他都是一样的,唯一没考虑到的就是 开始回溯的情况;还有一开始的boolean返回值!

已经出现了 每个位置都放不了的情况,就直接返回就好了!不用往下,boolean

        for(int i = 0;i < 9;i++){
            for(int j = 0;j < 9;j++){
                if(board[i][j] == '.'){
                    for(char k = '1';k <= '9';k++){
                        if(isTrue(board,i,j,k)){
                            board[i][j] = k;
                            if (backTrack(board)) return true;
                            board[i][j] = '.';//回溯
                        }
                    }
                    return false;
                }
            }
        }
        return true;

2)力扣答案

用数组实现位置的判断

但是该题不可避免的一个处理!

将递归方法的返回值设置为 boolean!

代码

1)回溯:参考代码回想录

class Solution {
    //不要结果集,只用更改棋盘即可
    public void solveSudoku(char[][] board) {
        //传入的即一个 类似棋盘的 二维数组,不用自己声明,模仿N皇后问题
        backTrack(board);
    }
    //回溯方法;可以在原方法中进行
    boolean backTrack(char[][] board){
        //结束条件就是棋盘没有 . ;因为不知道原来有多少 .

        for(int i = 0;i < 9;i++){
            for(int j = 0;j < 9;j++){
                if(board[i][j] == '.'){
                    for(char k = '1';k <= '9';k++){
                        if(isTrue(board,i,j,k)){
                            board[i][j] = k;
                            if (backTrack(board)) return true;
                            board[i][j] = '.';//回溯
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    }
    //判断条件
    /**
    传入棋盘、行、列,也就是要放置的位置
    value表示要放置的值!
     */
    boolean isTrue(char[][] board,int row,int col,int value){
        //同一行和同一列好判断
        for(int i = 0;i < 9;i++){
            if(board[row][i] == value) return false;
        }
        for(int i = 0;i < 9;i++){
            if(board[i][col] == value) return false;
        }
        //3 * 3空间内的判断;也就是有 9个区域,使用 row和col判断所属的区域!
        //确定for for循环的区间:0、3、6三个,怎么确定;使用 row - row % 3也可以
        int r = (row / 3) * 3;
        int c = (col / 3) * 3;
        for(int i = 0;i < 3;i++){
            for(int j = 0;j < 3;j++){
                if(board[r + i][c + j] == value) return false;
            }
        }
        return true;
    }
}

2)力扣:用数组记录,某行某列或某块是否出现过某值

class Solution {
    public void solveSudoku(char[][] board) {

        // 三个布尔数组 表明 行, 列, 还有 3*3 的方格的数字是否被使用过
        boolean[][] rowUsed = new boolean[9][10];
        boolean[][] colUsed = new boolean[9][10];
        boolean[][][] boxUsed = new boolean[3][3][10];
        // 初始化
        for(int row = 0; row < board.length; row++){
            for(int col = 0; col < board[0].length; col++) {
                if(board[row][col] == '.') continue;
                int num = board[row][col] - '0';
                rowUsed[row][num] = colUsed[col][num] = boxUsed[row/3][col/3][num] = true;
            }
        }
        // 递归尝试填充数组 
        recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, 0, 0);
    }
    
    private boolean recusiveSolveSudoku(char[][]board, boolean[][]rowUsed, boolean[][]colUsed, boolean[][][]boxUsed, int row, int col){
        // 边界校验, 如果已经填充完成, 返回true, 表示一切结束
        if(col == board[0].length){
            col = 0;
            row++;
            //在这儿实现 行的增加
            if(row == board.length) return true;
        }
        // 是空则尝试填充, 否则跳过继续尝试填充下一个位置
        if(board[row][col] == '.') {
            // 尝试填充1~9
            for(int num = 1; num <= 9; num++){
                if(rowUsed[row][num] || colUsed[col][num] || boxUsed[row/3][col/3][num]) continue;
                rowUsed[row][num] = true;
                colUsed[col][num] = true;
                boxUsed[row/3][col/3][num] = true;
                    
                board[row][col] = (char)('0' + num);
                if(recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1)) return true;
                board[row][col] = '.';
                    
                rowUsed[row][num] = false;
                colUsed[col][num] = false;
                boxUsed[row/3][col/3][num] = false;
            }
        } else {
            //在这儿实现 列的增加,同上面递归处
            return recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1);
        }
        return false;
    }
}
作者:I_use_java
链接:https://leetcode-cn.com/problems/sudoku-solver/solution/hui-su-fa-jie-shu-du-by-i_use_python/
来源:力扣(LeetCode)
举报

相关推荐

0 条评论