leetcode-------解數獨(回溯法)

如:

方法:回溯法:

回溯法的思想就是:對於一個問題有多個選擇方式,先選擇一個方式執行下去,若在執行過程中,發現不符合規則,則回退,回到選擇方式的步驟,進而選擇其他方式,繼續試。

重要:對於回溯法,一定會有個[規則],這個[規則]將會決定是否回退,所以當我們在使用回溯法時,一定要留意能否構建[規則]

如這一題,在數獨中,規則就是:

1. 在同一列和同一行中,不能出現一樣的數字。

2. 在同一個九宮格中,也不難出現同樣的數字。

所以我們需要用代碼構建規則:

def ok(self,board,i:int,j:int,x:str) -> bool:
        for t in range(9):
                if board[t][j] == x:return False  #(i,j)的同一列中是否已經出現x
                if board[i][t] == x:return False  #(i,j)的同一行中是否已經出現x
                if board[i//3* 3 + t//3][j//3*3 + t%3] == x: return False  #(i,j)的同一個九宮格中是否已經出現x
        return True  

然後我們進入進一步的討論:

在回溯法中,我們需要構造一個[鏈式標籤](這是我的說法),意思是:噹噹前有多種方式可以選擇時,我們隨機選一種,但並不清楚這種方式是否選得正確,所以當前狀態的正確性是由接下去的步驟決定的,若在下面的步驟中,發現與現在的規則不相符,則表明上一步的選擇是False的,所以回退到上一步驟,選擇其他方式。 要想獲得True,只有一種可能,就是程序能順利執行到結束,所有的選擇都與規則相符,纔會返回True。否則中間只要有一步錯了,就會返回False,一返回False就要回退重新選擇。

那如果實現這種方式呢?答案是用遞歸。代碼如下:

代碼:

class Solution:
    def solveSudoku(self, board) -> None:
        self.sudoke(board,0,0)
    def sudoke(self,board,i:int,j:int):
        if j<=8: #若列沒有越界
            if board[i][j] != ".": #當前位置若不爲空,不需要填入數字,直接去下一個位置
                if i<8:  #若未到最後一行,則到下一行的位置
                    if(self.sudoke(board,i+1,j)):return True
                else:    #若已經是最後一行,則到下一列的起始位置
                    if(self.sudoke(board,0,j+1)):return True
                return False
            else:   #當前位置爲空,需要填入數字
                for x in range(1,10):   #從1-9選數字填入空格
                    if not self.ok(board,i,j,str(x)):continue
                    board[i][j] = str(x)
                    if i<8:  #若未到最後一行,則到下一行的位置
                        if(self.sudoke(board,i+1,j)):return True
                    else:    #若已經是最後一行,則到下一列的起始位置
                        if(self.sudoke(board,0,j+1)):return True
                    board[i][j] = '.'   #若上訴步驟返回false,則清空當前位置填入的數字
                return False   #若1-9的9個數字都不符合填入規則,則返回False
        return True
    #判斷條件:判斷x能不能被填入
    def ok(self,board,i:int,j:int,x:str) -> bool:
        for t in range(9):
                if board[t][j] == x:return False  #(i,j)的同一列中是否已經出現x
                if board[i][t] == x:return False  #(i,j)的同一行中是否已經出現x
                if board[i//3* 3 + t//3][j//3*3 + t%3] == x: return False  #(i,j)的同一個九宮格中是否已經出現x
        return True  #若x符合填入條件,返回True。否則返回False

board = [['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']]
s = Solution()
s.solveSudoku(board)
for x in board:
    print(x)

運行效果:

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