leetcode-37-解数独
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
一个数独。
答案被标成红色。
Note:
给定的数独序列只包含数字 1-9 和字符 '.' 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
思路
数独的解法肯定是回溯法,也可以理解成DFS,对于数独而言一个就是有限编程(每个位置的选择并不是都是0-9),一个就是回溯
类似人的思考方式去尝试,行,列,还有 3*3 的方格内数字是 1~9 不能重复。
我们尝试填充,如果发现重复了,那么擦除重新进行新一轮的尝试,直到把整个数组填充完成。
算法步骤:
- 数独首先行,列,还有 3*3 的方格内数字是 1~9 不能重复。
- 声明布尔数组,表明行列中某个数字是否被使用了, 被用过视为 true,没用过为 false。
- 初始化布尔数组,表明哪些数字已经被使用过了。
- 尝试去填充数组,只要行,列, 还有 3*3 的方格内 出现已经被使用过的数字,我们就不填充,否则尝试填充。
- 如果填充失败,那么我们需要回溯。将原来尝试填充的地方改回来。
- 递归直到数独被填充完成。
# DFS
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
col = [set() for i in range(9)]
row = [set() for i in range(9)]
sqr = [[set() for i in range(3)] for i in range(3)]
for i in range(9):
for j in range(9):
if board[i][j] != '.':
col[j].add(board[i][j])
row[i].add(board[i][j])
sqr[i//3][j//3].add(board[i][j])
def dfs(i, j):
if board[i][j] != '.':
if i == 8 and j == 8:
self.flag = True
return
if j < 8:
dfs(i, j+1)
else:
dfs(i+1, 0)
return
for ch in range(1, 10):
ch = str(ch)
if ch not in col[j] and ch not in row[i] and ch not in sqr[i//3][j//3]:
#print(i, j, ch)
col[j].add(ch)
row[i].add(ch)
sqr[i//3][j//3].add(ch)
board[i][j] = ch
if i == 8 and j == 8:
self.flag = True
return
if j < 8:
dfs(i, j+1)
else:
dfs(i+1, 0)
if self.flag: return
board[i][j] = '.'
col[j].remove(ch)
row[i].remove(ch)
sqr[i//3][j//3].remove(ch)
self.flag = False
dfs(0, 0)