题目
https://leetcode-cn.com/problems/sudoku-solver/
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字1-9在每一行只能出现一次。
数字1-9在每一列只能出现一次。
数字1-9在每一个以粗实线分隔的3x3宫内只能出现一次。
空白格用 '.' 表示。
一个数独。
答案被标成红色。
Note:
给定的数独序列只包含数字 1-9 和字符 '.' 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
解题思路
- DFS + Backtracking
- 使用3个列表存储行、列、格的已有数字状态。
- 为了代码精简,将几个常用逻辑提炼为函数了。
- 先根据当前情况,初始化3个列表。
- 然后是标准回溯框架:
- 一进来先判断是否到底了,
- 然后得出下一步的坐标,
- 如果当前位置有数字,在下一步坐标上递归调用backtracking函数
- 如果当前位置是空白,那么循环遍历1-9
- 先看该数字是否违和
- 如果OK,就更新3个列表,并在数独表格中设置该数字
- 然后在下一步坐标上递归调用backtracking函数
- 如果返回False,则恢复3个列表,并擦掉数独表格中填入的数字
- 到此返回False
- 主程序入口:backtracking(0,0)
代码
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
row_list = [[False]*10 for _ in range(9)]
col_list = [[False]*10 for _ in range(9)]
grid_list = [[False]*10 for _ in range(9)]
# - get grid index
def get_grid_index(row,col):
return (row//3)*3 + col//3
# - set state to value (True/False)
def set_state(row, col, num, value):
row_list[row][num] = value
col_list[col][num] = value
grid_list[get_grid_index(row, col)][num] = value
# - init state
for row in range(9):
for col in range(9):
c = board[row][col]
if c != '.':
set_state(row, col, int(c), True)
# - check if num is valid at (row, col)
def is_valid(row, col, num):
return not any([
row_list[row][num],
col_list[col][num],
grid_list[get_grid_index(row,col)][num]
])
# - backtracking
def backtracking(row, col):
# - exit if out of boundary
if row == 9:
return True
# - get next position
next_col = (col + 1) % 9
next_row = row+1 if next_col==0 else row
# - only expand for '.'
c = board[row][col]
if c != '.':
return backtracking(next_row, next_col)
# - try 1..9
for i in range(1,10):
if not is_valid(row, col, i): continue
# - update state
set_state(row, col, i, True)
board[row][col] = '%s' % i
# - go to next pos
if backtracking(next_row, next_col):
return True
# - restore state
set_state(row, col, i, False)
board[row][col] = '.'
return False
# - backtracking from (0,0)
backtracking(0,0)