【LeetCode】:解数独【困难】

https://leetcode.cn/problems/sudoku-solver/


这道题是关于编写程序解决数独问题,以下是详细思路:

一、理解数独规则

  1. 行规则:数字1 - 9在每一行只能出现一次。这意味着在填写数独时,每行的九个格子中不能有重复的数字。
  2. 列规则:数字1 - 9在每一列只能出现一次。同理,每列的九个格子也不能有重复数字。
  3. 宫规则:数字1 - 9在每一个以粗实线分隔的3x3宫内只能出现一次。整个数独盘面被分成了九个3x3的小宫格,每个宫内的数字也不能重复。

二、解题方法(编程角度)

  1. 数据结构选择
    • 可以使用二维数组来表示数独盘面,例如int[][] sudoku = new int[9][9];,数组中的每个元素表示对应位置的数字,空白格用特定值(如0或题目中的.)表示。
  2. 算法思路
    • 回溯法 :这是解决数独问题常用的方法。
      • 从数独盘面的第一个空白格开始,尝试填入1 - 9中的一个数字,然后检查该数字是否满足行、列和宫的规则。
      • 如果满足规则,继续处理下一个空白格;如果不满足,就回溯到上一个空白格,尝试其他数字。
      • 重复这个过程,直到所有空白格都被填满且满足数独规则。
    • 优化
      • 在尝试填入数字时,可以先根据当前已有的数字,确定每个空白格可能填入的数字范围,减少不必要的尝试。例如,某一行已经有了1、2、3、4、5,那么这一行的空白格就只能填6、7、8、9,这样可以提高算法效率。

三、示例分析(以给定示例1为例)

  1. 首先观察示例中已有的数字,比如第一行有5、3、7,那么这一行剩下的空白格就不能再填这三个数字。
  2. 再看第一列有5、6、8,所以第一列的空白格也不能填这三个数字。
  3. 对于第一个3x3宫(左上角的宫),已有5、3、7、6,那么这个宫内的空白格只能从剩下的数字中选择。
  4. 按照这样的思路,逐步分析每个空白格,通过回溯法不断尝试和调整,最终完成整个数独的求解。

通过以上思路和方法,就可以编写程序来解决数独问题啦。在实际编程中,还需要注意代码的细节和边界情况的处理,以确保程序的正确性和高效性。

cpp 复制代码
class Solution {
    bool row[9][9];      // 用于记录每行中数字 1 - 9 的使用情况
                         // line[i][digit]为true表示第i行已经使用了数字digit
                         // digit取值范围是 0 - 8,对应实际数字 1 - 9
    bool col[9][9];      // 用于记录每列中数字 1 - 9 的使用情况
                         // column[j][digit]为true表示第j列已经使用了数字digit
    bool block[3][3][9]; // 用于记录每个 3x3 的小方块中数字 1 - 9
                         // 的使用情况block[i / 3][j / 3][digit]为true表示第(i /
                         // 3, j / 3)个小方块已经使用了数字digit
    bool valid;          // 用于标记当前的数独解是否有效
    vector<pair<int, int>> space; // 一个向量 用于存储数独中空白位置的坐标
public:
    void dfs(vector<vector<char>>& board, int pos) {
        if (pos == space.size()) {
            valid = true;
            return;
        }
        auto& [i, j] = space[pos]; // 获取当前要填充的空白位置的坐标(i, j);
        for (int digit = 0; digit < 9 && !valid; ++digit) {
            if (!row[i][digit] && !col[j][digit] &&
                !block[i / 3][j / 3][digit]) {
                row[i][digit] = col[j][digit] = block[i / 3][j / 3][digit] =
                    true;
                board[i][j] =
                    digit + '0' +
                    1; // 为了将这个数字 digit 以字符形式存储回数独板 board 中
                       // 需要将其转换回字符 这里利用了字符编码的特性 字符 '0'
                       // 的 ASCII 码值是一个固定值 例如在 ASCII 码中是 48 将
                       // digit 加上 '0' 就可以得到对应数字字符的 ASCII 码值
                       // 例如 当 digit 为 0 时,digit + '0' 就得到了字符 '0' 的
                       // ASCII 码值 当 digit 为 1 时,digit + '0' 就得到了字符
                       // '1' 的 ASCII 码值 以此类推
                dfs(board, pos + 1);
                row[i][digit] = col[j][digit] = block[i / 3][j / 3][digit] =
                    false; // 恢复现场;
            }
        }
    }
    void solveSudoku(vector<vector<char>>& board) {
        memset(row, false, sizeof(row));
        memset(col, false, sizeof(col));
        memset(block, false, sizeof(block));
        valid = false;
        // 通过两个嵌套的循环遍历数独板board 如果当前位置board[i][j]是空白 即==
        // '.' 将其坐标(i, j)添加到spaces向量中 否则
        // 将当前位置的数字转换为对应的索引digit board[i][j] - '0' - 1
        // 并将该数字在相应的行 列和小方块中的使用标记设置为true
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') {
                    space.emplace_back(i, j);
                } else {
                    int digit = board[i][j] - '0' - 1;
                    // 而数独中的数字是从 1 到 9
                    // 为了能方便地将数独中的数字与这些标记数组的索引对应起来
                    // 需要将字符转换后的数字再减去 1 这样 数独中的数字 1
                    // 就对应标记数组中的索引 0 数字 2 对应索引 1 以此类推 数字
                    // 9 对应索引 8
                    row[i][digit] = col[j][digit] = block[i / 3][j / 3][digit] =
                        true;
                }
            }
        }
        dfs(board, 0);
    }
};
相关推荐
BingLin-Liu9 分钟前
备考蓝桥杯:顺序表相关算法题
算法·职场和发展·蓝桥杯
水水阿水水9 分钟前
第一章:C++是C语言的扩充(一)
linux·c语言·数据结构·c++·算法
40岁的系统架构师1 小时前
5 分布式ID
分布式·算法
狄加山6756 小时前
数据结构(查找算法)
数据结构·数据库·算法
陌然。。7 小时前
【701. 二叉搜索树中的插入操作 中等】
数据结构·c++·算法·leetcode·深度优先
Ritsu栗子7 小时前
代码随想录算法训练营day25
c++·算法
是十一月末7 小时前
机器学习之过采样和下采样调整不均衡样本的逻辑回归模型
人工智能·python·算法·机器学习·逻辑回归
生信碱移7 小时前
万字长文:机器学习的数学基础(易读)
大数据·人工智能·深度学习·线性代数·算法·数学建模·数据分析
疯狂小料7 小时前
Python3刷算法来呀,贪心系列题单
开发语言·python·算法