Bootstrap

leetcode36:有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 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"]]
输出:true

示例 2:

输入:board = 
[["8","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"]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

提示:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] 是一位数字(1-9)或者 '.'

步骤 1:题目分析与定义

问题定义:
给定一个 9×99 \times 99×9 的数独棋盘,验证棋盘上已填入的数字是否符合数独规则:

  1. 每行中数字 1-9 不能重复。
  2. 每列中数字 1-9 不能重复。
  3. 每个 3×33 \times 33×3 的小方格内数字 1-9 不能重复。

输入:

  • 一个 9×99 \times 99×9 的二维数组 board,其中每个元素为字符 '1''9''.'(代表空格)。

输出:

  • 布尔值,true 表示数独有效,false 表示无效。

限制与边界条件:

  1. 棋盘大小固定为 9×99 \times 99×9。
  2. 数组中仅包含 '1''9''.'
  3. 棋盘可能只部分填充。

步骤 2:解题思路与算法设计

这是一个约束检查问题,解决方案需要验证三个条件(行、列、小方格)是否满足数独规则。考虑到问题的性质,使用集合存储已经出现的数字是较为高效的选择,这可以确保检查重复的操作在 O(1)O(1)O(1) 时间内完成。

方案概述
  1. 检查行:对于每一行,用一个集合来记录该行中已出现的数字。如果数字重复出现,则判定数独无效。
  2. 检查列:对每一列进行类似的检查,使用一个集合记录已出现的数字。
  3. 检查 3×33 \times 33×3 小方格:每个小方格可用集合记录出现的数字。遍历每个小方格的所有格子,检测是否有重复的数字。
最佳算法设计

我们可以在一次遍历中完成所有检查,采用三个集合数组来分别跟踪行、列和小方格中的数字。如下:

  1. 定义三个集合数组 rows[9]cols[9]boxes[9],分别用于存储行、列和小方格内的数字。
  2. 遍历整个棋盘,对于每个非 '.' 的格子,检查并更新相应的集合:
    • 如果数字已存在于对应的行集合 rows[row]、列集合 cols[col] 或小方格集合 boxes[box_index] 中,则返回 false
    • 否则,将数字添加到相应集合中。

复杂度分析:

  • 时间复杂度:O(81)=O(1)O(81) = O(1)O(81)=O(1),因为数独大小固定为 9×99 \times 99×9。
  • 空间复杂度:O(81)=O(1)O(81) = O(1)O(81)=O(1),我们只需三个固定大小的集合数组。
算法代码框架

该算法是一种直接的遍历与检查法,能够高效地检查数独有效性。


步骤 3:C++ 代码实现

步骤 4:解题启发与优化

启发:

  1. 集合的应用:使用集合来检测重复性操作是非常高效的,尤其在需要频繁检查和插入的场景下,集合的查找时间复杂度为 O(1)O(1)O(1)。
  2. 空间优化:可以进一步优化空间,将集合换成整型数组记录出现次数,但集合的可读性和代码简洁度较高。

效率提升:该算法遍历一次数独即可完成检查,适用于固定大小的棋盘,满足时间和空间复杂度需求,适合直接应用于生产环境。


步骤 5:算法实际应用

应用场景: 该算法可以应用于任何需要有效性检查和数据完整性验证的场景。例如在多维数据存储中,确保数据在行、列、或区域内不重复的约束要求。

实际应用示例: 在 仓库库存管理系统 中,可能需要确保某些特定区域(例如仓储格)内不会重复存放同一批次的产品。类似数独规则,每个仓储格有行、列、区域约束。这种算法可以用来自动检测仓库分区设置的有效性,避免重复存储。

实现方法: 设计一个与仓库布局一致的二维数组,模拟数独的行、列和区域约束,利用集合记录每个存储区域中已存入的批次号,防止重复存放,提高仓储效率。

;