25.解数独(hard)

1.题目链接:37. 解数独 - 力扣(LeetCode)37. 解数独 - 编写一个程序,通过填充空格来解决数独问题。数独的解法需 遵循如下规则: 1. 数字 1-9 在每一行只能出现一次。 2. 数字 1-9 在每一列只能出现一次。 3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)数独部分空格内已填入了数字,空白格用 '.' 表示。 示例 1:[https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2021/04/12/250px-sudoku-by-l2g-20050714svg.png]输入: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"]]输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]解释:输入的数独如上图所示,唯一有效的解决方案如下所示:[ https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2021/04/12/250px-sudoku-by-l2g-20050714_solutionsvg.png] 提示: * board.length == 9 * board[i].length == 9 * board[i][j] 是一位数字或者 '.' * 题目数据 保证 输入数独仅有一个解https://leetcode.cn/problems/sudoku-solver/description/

2.题目描述:

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

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

输入: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"]]​

输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],

["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"], ["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"], ["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"], ["3","4","5","2","8","6","1","7","9"]]​

解释:输入的数独如上图所示,唯一有效的解决方案如下所示:

提示:

board.length == 9​

board[i].length == 9​

board[i][j] 是一位数字或者 '.'​

题目数据 保证 输入数独仅有一个解​

3. 解法:

算法思路:

为了存储每个位置的元素,我们需要定义一个二维数组。首先,我们记录所有已知的数据,然后遍历所有需要处理的位置,并遍历数字 1~9。对于每个位置,我们检查该数字是否可以存放在该位置,同时检查行、列和九宫格是否唯一。

我们可以使用一个二维数组来记录每个数字在每一行中是否出现,一个二维数组来记录每个数字在每一列中是否出现。对于九宫格,我们可以以行和列除以 3 得到的商作为九宫格的坐标,并使用一个三维数组来记录每个数字在每一个九宫格中是否出现。在检查是否存在冲突时,只需检查行、列和九宫格里对应的数字是否已被标记。如果数字至少有一个位置(行、列、九宫格)被标记,则存在冲突,因此不能在该位置放置当前数字。

特别地,在本题中,我们需要直接修改给出的数组,因此在找到一种可行的方法时,应该停止递归,以防止正确的方法被覆盖。

初始化定义:
1. 定义行、列、九宫格标记数组以及找到可行方法的标记变量,将它们初始化为 false。​2. 定义一个数组来存储每个需要处理的位置。

3. 将题目给出的所有元素的行、列以及九宫格坐标标记为 true。​4. 将所有需要处理的位置存入数组。

递归函数设计:void dfs(vector<vector<char>>& board, int pos)​参数:pos(当前需要处理的坐标);​
返回值:无;
函数作用:在当前坐标填入合适数字,查找数独答案。

递归流程如下:
1. 结束条件:已经处理完所有需要处理的元素。如果找到了可行的解决方案,则将标记变量更新为 true 并返回。​
2. 获取当前需要处理的元素的行列值。

3. 遍历数字 1~9。如果当前数字可以填入当前位置,并且标记变量未被赋值为 true,则将当前位置的行、列以及九宫格坐标标记为 true,将当前数字赋值给 board 数组中的相应位置元素,然后对下一个位置进行递归。

4. 递归结束时,撤回标记。

Java算法代码:

class Solution {
    boolean [][] row,col;
    boolean [][][] grid;

    public void solveSudoku(char[][] board) {
        row = new boolean[9][10];
        col = new boolean[9][10];
        grid = new boolean[3][3][10];

        //初始化
        for(int i = 0; i< 9;i++){
            for(int j = 0; j < 9; j++){
                if(board[i][j] != '.'){
                    int num = board[i][j] -'0';
                    row[i][num] = col[j][num] = grid[ i / 3][j / 3] [num] =true;
                }
            }
        }
        dfs(board);
    }
    public boolean dfs(char [][] board){
        for(int i =0; i<9;i++){
            for(int j =0;j<9;j++){
                if(board[i][j]=='.'){
                    //填数字
                    for(int num = 1;num <= 9; num++){
                        if(!row[i][num] && !col[j][num] && !grid[i/3][j/3][num]){
                            board[i][j] = (char) ('0' + num);
                            row[i][num] = col[j][num] = grid[i/3][j/3][num] = true;
                            if(dfs(board) == true ) return true; //重点理解
                            //恢复现场
                            board[i][j] = '.';
                            row[i][num] = col[j][num] = grid[i/3][j/3][num] = false;
                            
                        }
                    }
                    return false;//重点理解
                }
            }
        }
        return true;//重点理解
    }
}

运行结果:

递归展开:

这里笔者其实都没有展开多少就理解, 

先去看读者的上一个题,这里开始的初始化(就是先把数独的已经填数的来做标记,也就是说,这里已经填了一个数,那么这一行,这一列,这个九宫格,都不能再放这个数)

重点理解,几行返回值

还有递归调用的if

逻辑展开:

当细节都明白的时候,就会知道,数独求解,就是再已经标记好的数独上去遍历和尝试(进而寻找真正解,遇到错误解,就会回溯)。

---------------------------------------------------------------------------------------------------------------------------------

记住,相信你的递归函数,它可以做到!

记住,不理解时候,去尝试手动展开!

记住,逻辑展开(你不可能对所有的题目都进行手动展开)!

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值