当前位置: 首页 > news >正文

39- 有效的数独

请你判断一个 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)或者 '.'
     

方法一:分别检查行、列和 3x3 宫格

此方法依次对每一行、每一列以及每一个 3x3 宫格进行检查,利用集合来记录已出现的数字,若发现重复数字则判定数独无效。

function isValidSudoku(board: string[][]): boolean {// 检查每一行for (let i = 0; i < 9; i++) {const rowSet = new Set<string>();for (let j = 0; j < 9; j++) {const cell = board[i][j];if (cell!== '.') {if (rowSet.has(cell)) {return false;}rowSet.add(cell);}}}// 检查每一列for (let j = 0; j < 9; j++) {const colSet = new Set<string>();for (let i = 0; i < 9; i++) {const cell = board[i][j];if (cell!== '.') {if (colSet.has(cell)) {return false;}colSet.add(cell);}}}// 检查每一个 3x3 宫格for (let i = 0; i < 9; i += 3) {for (let j = 0; j < 9; j += 3) {const boxSet = new Set<string>();for (let x = i; x < i + 3; x++) {for (let y = j; y < j + 3; y++) {const cell = board[x][y];if (cell!== '.') {if (boxSet.has(cell)) {return false;}boxSet.add(cell);}}}}}return true;
}
复杂度分析
  • 时间复杂度:(O(1)),由于数独的规模固定为 9x9,代码需遍历 81 个单元格,操作次数恒定。
  • 空间复杂度:(O(1)),在检查行、列和 3x3 宫格时,集合最多存储 9 个元素,属于常数级空间复杂度。

方法二:一次遍历检查

该方法在一次遍历数独的过程中,同时记录每一行、每一列以及每一个 3x3 宫格中数字的出现情况,使用三个二维数组来分别存储这些信息。

function isValidSudoku(board: string[][]): boolean {const rows: boolean[][] = Array.from({ length: 9 }, () => Array(9).fill(false));const cols: boolean[][] = Array.from({ length: 9 }, () => Array(9).fill(false));const boxes: boolean[][] = Array.from({ length: 9 }, () => Array(9).fill(false));for (let i = 0; i < 9; i++) {for (let j = 0; j < 9; j++) {const cell = board[i][j];if (cell!== '.') {const num = parseInt(cell) - 1;const boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3);if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) {return false;}rows[i][num] = true;cols[j][num] = true;boxes[boxIndex][num] = true;}}}return true;
}
复杂度分析
  • 时间复杂度:(O(1)),同样因为数独大小固定,仅需遍历 81 个单元格。
  • 空间复杂度:(O(1)),使用的三个二维数组大小均为 9x9,是常数级的空间开销。

方法三:使用哈希表优化

通过使用哈希表来存储每一行、每一列和每一个 3x3 宫格中数字的出现次数,在遍历过程中更新哈希表并检查是否有重复数字。

function isValidSudoku(board: string[][]): boolean {const rows: Map<number, Set<string>> = new Map();const cols: Map<number, Set<string>> = new Map();const boxes: Map<number, Set<string>> = new Map();for (let i = 0; i < 9; i++) {rows.set(i, new Set());cols.set(i, new Set());boxes.set(i, new Set());}for (let i = 0; i < 9; i++) {for (let j = 0; j < 9; j++) {const cell = board[i][j];if (cell!== '.') {const boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3);if (rows.get(i)!.has(cell) || cols.get(j)!.has(cell) || boxes.get(boxIndex)!.has(cell)) {return false;}rows.get(i)!.add(cell);cols.get(j)!.add(cell);boxes.get(boxIndex)!.add(cell);}}}return true;
}
复杂度分析
  • 时间复杂度:(O(1)),遍历 9x9 的数独网格,操作次数固定。
  • 空间复杂度:(O(1)),哈希表最多存储 9 行、9 列和 9 个 3x3 宫格的信息,每个集合最多存储 9 个元素,为常数级空间复杂度。

你可以使用以下代码测试上述函数:

const board1 = [["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"]
];
console.log(isValidSudoku(board1));const board2 = [["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"]
];
console.log(isValidSudoku(board2));

 

相关文章:

  • Vue的Diff算法原理
  • APang网联科技项目报告(服务器域管理篇)
  • Flink-01学习 介绍Flink及上手小项目之词频统计
  • java IO/NIO/AIO
  • L2-033 简单计算器满分笔记
  • 十三种通信接口芯片——《器件手册--通信接口芯片》
  • 解决“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接“问题
  • 【C++面向对象】封装(下):探索C++运算符重载设计精髓
  • C++每日训练 Day 16:构建 GUI 响应式信号机制(面向初学者)
  • android liveData observeForever 与 observe对比
  • class的访问器成员
  • TAS(Thin-Agent服务)的先决条件与安装指南
  • 安当ASP身份认证系统:低成本方案实现堡垒机/防火墙/VPN二次认证升级
  • 《Learning Langchain》阅读笔记2-基于 Gemini 的 Langchain PromptTemplate 实现方式
  • [C++] STL中的向量容器<vector>附加练习
  • 赛灵思 XCVU440-2FLGA2892E XilinxFPGA Virtex UltraScale
  • Qt 信号与槽复习
  • 【Springboot】项目Demo
  • git rebase的使用
  • 某客户ORA-600 导致数据库反复重启问题分析
  • 美国明尼苏达州发生山火,过火面积超80平方公里
  • 杭州钱塘区3宗涉宅用地均以底价成交,共计成交金额25.73亿元
  • 董军同法国国防部长举行会谈
  • 中美发布日内瓦经贸会谈联合声明达成关税共识,外交部回应
  • A股高开高走:沪指涨0.82%,创指涨2.63%,超4100股收涨
  • 著名学者黄修己去世,享年90岁