Loading [MathJax]/jax/output/HTML-CSS/jax.js

[Leetcode解題] Word Search - bfs/dfs解

11 February 2022
medium dp dfs bfs

題目

79. Word Search

解題思路

這題我們很直接會想要用BFS/DFS的解法來解,以每個點為起點去做搜尋,這樣時間複雜度為O(MN3L)M,N為棋盤的長寬,L為搜尋字串的長度,最差的情況來說,我們需要走訪M×N個點作為起點,每個點又需要走過L個點做探索,每個位置可以往上下左右走,所以最壞有43L1種可能。

錯誤思路

我們可以試著想一下有什麼地方是重複的計算,但先跟大家說下面的想法是錯的

假設我們的棋盤是

ABEOK CAOLL

而我們要搜索的字串為ABEOP,假設我們是用DFS,可以看到我們從第一個A(0,0)出發後,會試過:

ABEOKFail

ABEOLFail

之後我們到下一個A(1,1),也會去搜尋:

ABEOKFail

ABEOLFail

可以看到這兩個路徑通過同一個點B(0,1),之後的路徑是一模一樣的,所以當我們第一次搜索知道後面已經找不到時,第二次搜索應該就可以直接停止:

ABFail

ABFail

大家有發現這個想法錯誤在哪嗎?

因為我們兩次走到同個點B(0,1)的時候,棋盤的走訪狀態並不同,所以第一次探索的結果,並不能直接用在第二次,舉一個例子,假設我們今天想要搜索的字串為ABEOA,這樣從A(1,1)出發,經過B(0,1)是False,但從A(0,0)出發,卻可以是True,所以這個方法並不能適用。

解題思路

基本上的解法是採取DFS,除此之外我們要記錄棋盤是否走訪過的狀態,我們可以透過一個二維矩陣visited來紀錄,也可以直接將當前位置修改成一個非大寫字母的字元(因為題目有註明棋盤只會是大寫字母)。

實作

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        for i in range(len(board)):
            for j in range(len(board[0])):
                if self.dfs(board, i, j, word):
                    return True
        return False
        
    def dfs(self, board, i, j, word):
        if board[i][j] == "#" or board[i][j] != word[0]:
            return False
        if board[i][j] == word[0] and len(word) == 1:
            return True
        
        tmp = board[i][j]
        board[i][j] = "#"
        if i-1 >= 0 and self.dfs(board, i-1, j, word[1:]):
            return True
        if j+1 < len(board[0]) and self.dfs(board, i, j+1, word[1:]):
            return True
        if i+1 < len(board) and self.dfs(board, i+1, j, word[1:]):
            return True
        if j-1 >= 0 and self.dfs(board, i, j-1, word[1:]):
            return True
        board[i][j] = tmp
        return False