LeetCode 36. 有效的数独 - 解题思路与实现详解
LeetCode 36. 有效的数独 - 解题思路与实现详解
题目描述
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可:
- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
注意:
- 一个有效的数独(部分已被填充)不一定是可解的。
- 只需要根据以上规则,验证已经填入的数字是否有效即可。
- 空白格用 ‘.’ 表示。
解题思路分析
1. 问题理解
数独验证的核心是检查三个维度:
- 行检查:每一行中的数字1-9不能重复
- 列检查:每一列中的数字1-9不能重复
- 3x3宫格检查:每个3x3的小宫格中数字1-9不能重复
2. 关键思考点
2.1 如何处理空白格(‘.’)
空白格用’.'表示,在验证时需要考虑:
- 集合去重时会自动忽略’.’
- 需要正确计算有效数字的数量
2.2 3x3宫格的遍历
如何正确遍历9个3x3宫格是关键:
- 每个宫格的起始位置:(0,0), (0,3), (0,6), (3,0), (3,3), (3,6), (6,0), (6,3), (6,6)
- 使用双重循环:
for x in range(0, 9, 3): for y in range(0, 9, 3)
2.3 列数据的提取
Python中不能直接用board[:][y]
获取列,需要使用列表推导式:
column_y = [row[y] for row in board]
代码实现
方法一:集合验证法
class Solution:def isValidSudoku(self, board: list[list[str]]) -> bool:# 检查3x3宫格for x in range(0, 9, 3):for y in range(0, 9, 3):# 提取当前3x3宫格的所有元素grids = [board[x][y], board[x][y+1], board[x][y+2],board[x+1][y], board[x+1][y+1], board[x+1][y+2],board[x+2][y], board[x+2][y+1], board[x+2][y+2]]# 验证:去重后的数字个数 + 空白格个数 = 9if (len(set(grids)) + grids.count('.')) - 1 != 9:return False# 检查每一行for x in range(9):if (len(set(board[x])) + board[x].count('.')) - 1 != 9:return False# 检查每一列for y in range(9):column_y = [row[y] for row in board]if (len(set(column_y)) + column_y.count('.')) - 1 != 9:return Falsereturn True
方法二:哈希表优化法
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 i in range(9):for j in range(9):num = board[i][j]if num == '.':continue# 检查行if num in rows[i]:return Falserows[i].add(num)# 检查列if num in cols[j]:return Falsecols[j].add(num)# 检查3x3宫格box_index = (i // 3) * 3 + j // 3if num in boxes[box_index]:return Falseboxes[box_index].add(num)return True
关键知识点
1. Python集合操作
# 集合去重
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_numbers = set(numbers) # {1, 2, 3, 4, 5}# 集合长度
len(unique_numbers) # 5
2. 列表推导式
# 提取矩阵的列
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
column_0 = [row[0] for row in matrix] # [1, 4, 7]
column_1 = [row[1] for row in matrix] # [2, 5, 8]
3. 3x3宫格索引计算
# 计算(i,j)位置属于哪个3x3宫格
box_index = (i // 3) * 3 + j // 3# 宫格编号对应关系:
# 0 1 2
# 3 4 5
# 6 7 8
解题过程中的常见错误
1. 错误理解集合去重
# 错误示例
grids = ['.', '1', '2', '.', '3', '4', '5', '6', '7']
unique_count = len(set(grids)) # 8 (包含了'.')
# 正确做法
valid_count = len(set(grids)) + grids.count('.') - 1 # 7
2. 错误的列提取方式
# 错误示例
board = [[1,2,3], [4,5,6], [7,8,9]]
column = board[:][0] # 这样不会得到第一列# 正确做法
column = [row[0] for row in board] # [1, 4, 7]
3. 3x3宫格遍历错误
# 错误示例:没有在循环内重新计算grids
grids = [board[0][0], board[0][1], ...] # 只计算了一次
for x in range(0, 9, 3):for y in range(0, 9, 3):# 应该在这里重新计算grids
复杂度分析
时间复杂度
- 方法一:O(n²),其中n=9,需要遍历整个数独板
- 方法二:O(n²),但实际运行更快,因为使用哈希表查找
空间复杂度
- 方法一:O(1),只使用常数空间
- 方法二:O(n),需要存储行、列、宫格的哈希表
测试用例
# 测试用例1:有效数独
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"]
]
# 预期结果:True# 测试用例2:无效数独(第一行有重复)
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"]
]
# 预期结果:False
总结
这道题的核心在于:
- 理解数独规则:行、列、3x3宫格都不能有重复数字
- 正确处理空白格:'.'不影响验证,但需要正确计算
- 掌握Python语法:集合操作、列表推导式、矩阵操作
- 注意边界条件:确保所有情况都被正确验证
通过这道题,我学会了:
- 如何验证矩阵的多个维度
- 如何处理特殊字符(如’.')
- 如何正确提取矩阵的行和列
- 如何使用集合进行去重验证
这是一道很好的练习Python基础语法和逻辑思维的题目!
更新日期2025年8月31日