leetcode-37-解數獨

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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章