2020年4月5日 星期日

Leetcode題解 Python: Word Search II

Given a 2D board and a list of words from the dictionary, find all words in the board.
很像找詞遊戲,看看版面上有沒有要搜尋的詞。不過跟一般的規則不同的是,它可以轉彎。

此題列在 trie 章節內,所以自然而然將目標字詞寫入 trie 內,再用 y x 遍歷整個版面,把board[y][x]放入搜尋就可以了。

重複出現的字詞只算一個,所以找到的字詞放入 set 或是 dict當key,最後再取出來。

這題我是很快就解出來的,關鍵之處不是如何把詞放入 trie,而是搜尋要如何進行。

如果學過回溯法,應該很快就知道找路徑的寫法是該怎麼進行。


當遍歷整個版面,取得 y x,如果 board[y][x] 在 trie 內,就繼續往四週找,看四週的字是否有出現下一層。

因為限制不能回頭,所以用一個 memo 去紀錄步驟(座標),接下來就避免重複尋找已經走過的路徑。(if (y,x) in memo)

回溯法的關鍵寫法:是在往下遞迴之前才加入步驟,在遞迴結束後要刪除之前加入的步驟。這就像是回到上一步,再往下一個方向嘗試。

最終會將全部可走的都走過,再一一收回步驟,因此當搜尋完畢之後 memo 會是空的。
class Solution:
    def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        if board and board[0]:
            rows, cols = len(board), len(board[0]) 
            # create trie
            trie = {}
            for word in words:
                cur = trie
                for char in word:
                    if char not in cur:
                        cur[char] = {}
                    cur = cur[char]
                cur['end'] = word
            #
            memo = {*""}
            findWords = {*""}
            def search(y, x, level):                
                if board[y][x] in level:
                    level = level[board[y][x]]
                    if 'end' in level:
                        findWords.add(level['end'])                    
                    if y-1 >= 0 and (y-1,x) not in memo:
                        memo.add((y,x))
                        search(y-1, x, level)
                        memo.discard((y,x))
                    if x-1 >= 0 and (y,x-1) not in memo:
                        memo.add((y,x))
                        search(y, x-1, level)    
                        memo.discard((y,x))
                    if y+1 < rows and (y+1,x) not in memo:
                        memo.add((y,x))
                        search(y+1, x, level)
                        memo.discard((y,x))
                    if x+1 < cols and (y,x+1) not in memo:
                        memo.add((y,x))
                        search(y, x+1, level)    
                        memo.discard((y,x))
                            
            for y in range(rows):
                for x in range(cols):
                    memo.clear()
                    search(y, x, trie)
                    
            return list(findWords)