在问 · 算法题解

36. 有效的数独

题目描述

输入一个 9 x 9 的数独盘面 board,已填的格子是 '1' 到 '9',空格是 '.'。盘面可以只填了一部分。

只检查已填的数字是否冲突:同一行内、同一列内、以及 9 个不重叠的 3 x 3 小宫格内,每个数字都不能出现两次或以上。

没有冲突就返回 true,否则返回 false。不需要判断盘面能否被填完,没有冲突但无解的盘面也算有效。

示例 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

解释:与示例 1 相比只把左上角的 5 改成了 8,左上角的 3 x 3 宫格里出现了两个 8。

数据范围

  • board.length == 9
  • board[i].length == 9
  • board[i][j] 是 '1' 到 '9' 中的一个数字,或者 '.'。

解题思路

为 9 行、9 列、9 宫各准备一个哈希集合,共 27 个。按行逐格扫描:空格跳过;对数字 v,先算出宫号 b = (r//3)*3 + c//3,再查 v 是否已在 rows[r]、cols[c]、boxes[b] 任一集合中——在就说明重复,直接返回 false;否则把 v 同时加入这三个集合。全部扫完没有冲突就返回 true。

为什么正确

扫描到 (r,c) 之前,rows[i] / cols[j] / boxes[k] 恰好是已扫描过的格子中、第 i 行 / 第 j 列 / 第 k 宫出现过的数字集合,且其中没有重复。

复杂度分析

盘面固定 81 格,时间 O(81) = O(1),空间 27 个集合共 O(1)。若推广到 n×n,则时间 O(n²),空间 O(n²)。

易错点

宫号最容易算错:应是 (r//3)*3 + c//3,而不是 r//3 + c//3(会让不同宫撞号)或 r*3 + c。另外不要只检查行和列——两个相同数字可以既不同行也不同列,却位于同一宫。空格 '.' 必须跳过,不能当作字符加入集合。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        rows = [set() for _ in range(9)]
        cols = [set() for _ in range(9)]
        boxes = [set() for _ in range(9)]
        for r in range(9):
            for c in range(9):
                v = board[r][c]
                if v == '.':
                    continue
                b = (r // 3) * 3 + c // 3
                if v in rows[r] or v in cols[c] or v in boxes[b]:
                    return False
                rows[r].add(v)
                cols[c].add(v)
                boxes[b].add(v)
        return True

载入编辑器,自己跑一遍 →

哈希表 专题的其他题目

查看 哈希表 全部题目 →