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)