数独系列算法

目录

一、问题背景:数独的规则与挑战

二、有效的数独:高效验证算法

问题分析

算法实现

算法复杂度

三、解数独:回溯算法的经典应用

问题分析

算法实现

算法复杂度

四、两种算法的关联与区别

五、总结


数独作为经典的逻辑谜题,不仅是休闲益智的选择,也蕴含了丰富的算法设计思路。本文将围绕 "有效的数独" 验证和 "解数独" 两个问题,深入讲解其背后的算法逻辑与实现细节。

一、问题背景:数独的规则与挑战

数独是一个 9×9 的网格,需满足以下规则:

  • 数字 1-9每一行只能出现一次;
  • 数字 1-9每一列只能出现一次;
  • 数字 1-9每一个 3×3 子网格(共 9 个)内只能出现一次。

我们要解决两个核心问题:

  1. 有效的数独:验证已填入的数字是否符合规则(无需保证数独可解);
  2. 解数独:填充所有空格,得到一个符合规则的完整数独。

二、有效的数独:高效验证算法

问题分析

我们需要快速判断每一行、每一列、每一个 3×3 子网格内的数字是否唯一。最直观的思路是用三个数组分别记录行、列、子网格的数字出现情况

算法实现

cpp 复制代码
class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        // 三个数组分别记录:行、列、3×3子网格的数字出现情况
        bool rows[9][10] = {false};   // rows[i][num]:第i行是否出现过num
        bool cols[9][10] = {false};   // cols[j][num]:第j列是否出现过num
        bool grid[3][3][10] = {false};// grid[x][y][num]:第(x,y)个3×3子网格是否出现过num

        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] == '.') continue; // 空格跳过

                int num = board[i][j] - '0';
                // 若行、列或子网格中已出现该数字,直接返回无效
                if (rows[i][num] || cols[j][num] || grid[i/3][j/3][num]) {
                    return false;
                }

                // 标记该数字已出现
                rows[i][num] = cols[j][num] = grid[i/3][j/3][num] = true;
            }
        }
        return true;
    }
};

算法复杂度

  • 时间复杂度:O(1)(因为网格固定为 9×9,循环次数是常数);
  • 空间复杂度:O(1)(三个数组的大小固定)。

三、解数独:回溯算法的经典应用

问题分析

解数独需要填充所有空格 ,且每一步都要满足数独规则。这类 "尝试所有可能并回溯" 的问题,最适合用深度优先搜索(DFS)+ 回溯来解决。

算法实现

cpp 复制代码
class Solution {
public:
    // 三个数组记录行、列、3×3子网格的数字使用情况
    bool row[9][10] = {false}, col[9][10] = {false}, grid[3][3][10] = {false};

    void solveSudoku(vector<vector<char>>& board) {
        // 初始化:标记已存在的数字
        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); // 开始回溯求解
    }

    bool dfs(vector<vector<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] = num + '0'; // 填入数字
                            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; // 所有空格都填满,数独已解
    }
};

算法复杂度

  • 时间复杂度:最坏情况下为 O(981)(每个空格有 9 种可能,共 81 个空格),但实际中由于数独规则的约束,回溯会提前剪枝,效率远高于理论上界;
  • 空间复杂度:O(1)(数组大小固定)+ 递归栈深度 O(81)(最多递归 81 层)。

四、两种算法的关联与区别

维度 有效的数独 解数独
目标 验证已填数字是否合法 填充所有空格,得到合法数独
算法核心 遍历 + 哈希表(记录数字出现情况) 回溯 + 剪枝(尝试所有可能并回退)
时间复杂度 O(1)(固定 9×9 网格) 最坏 O(981),实际远低于此
应用场景 快速排查数独的合法性 需得到完整解的场景

五、总结

"有效的数独" 和 "解数独" 是数独问题的两个核心方向,分别体现了哈希表验证回溯剪枝的经典算法思想。

  • 对于 "有效性验证",利用三个数组记录行、列、子网格的数字出现情况,可在常数时间内完成判断;
  • 对于 "解数独",回溯算法是最直接的思路,通过 "尝试 - 验证 - 回溯" 的流程,逐步填充所有空格。

这两个问题的解法也为其他类似的 "约束满足问题"(如八皇后、迷宫求解)提供了参考,掌握它们的思路,能帮助你在更多算法场景中举一反三。

相关推荐
shangjian0076 小时前
AI大模型-评价指标-相关术语
人工智能·算法
Live&&learn7 小时前
算法训练-数据结构
数据结构·算法·leetcode
松岛雾奈.2308 小时前
机器学习--PCA降维算法
人工智能·算法·机器学习
电子_咸鱼8 小时前
【STL string 全解析:接口详解、测试实战与模拟实现】
开发语言·c++·vscode·python·算法·leetcode
sweet丶9 小时前
适合iOS开发的一种缓存策略YYCache库 的原理
算法·架构
是宇写的啊9 小时前
算法—滑动窗口
算法
风筝在晴天搁浅9 小时前
代码随想录 509.斐波那契数
数据结构·算法
落落落sss9 小时前
java实现排序
java·数据结构·算法
limenga10210 小时前
支持向量机(SVM)深度解析:理解最大间隔原理
算法·机器学习·支持向量机
coder江10 小时前
二分查找刷题总结
算法