# 212. Word Search II #### Difficulty: Hard link: https://leetcode.com/problems/word-search-ii/ ### 1. Backtracking + Trie ~~#### $O(1)$ runtime, $O(1)$ space~~ 相較於前一題[79. Word Search](https://leetcode.com/problems/word-search/),需要檢查的word變多了,如果直接沿用前一題的演算法,一個個word去搜尋會很沒效率,這是可以優化的地方。 希望優化的方向是,同樣跑一次全board的search,但backtracking函數能檢查到每個word。 最簡單的方式是,每次函數都O(k)掃過每個word檢查,但這樣可能會太慢。希望能只檢查走到目前為止還相符的word,而且排除掉已經成功找到過的word,能滿足這樣需求的資料結構就是Trie。 dfs用iterative的做法會比recursive還要快。 ##### python ```python= class TrieNode: def __init__(self): self.children = collections.defaultdict(TrieNode) self.is_word = False self.count = 0 class Trie: def __init__(self): self.root = TrieNode() def insert(self, word): node = self.root node.count += 1 for char in word: node = node.children[char] node.count += 1 node.is_word = True def remove(self, word): node = self.root node.count -= 1 for char in word: pre_node = node node = node.children[char] node.count -= 1 if node.count == 0: del pre_node.children[char] node.is_word = False class Solution: def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: trie = Trie() board_cnt = Counter([ch for row in board for ch in row]) for word in words: word_cnt = Counter(word) # optimization if any(word_cnt[ch] > board_cnt[ch] for ch in word_cnt): continue trie.insert(word) result = [] m, n = len(board), len(board[0]) def dfs(x, y, path, node): if node.is_word: result.append(path) trie.remove(path) board[x][y] = "#" for nx, ny in [[x-1, y], [x+1, y], [x, y-1], [x, y+1]]: if 0 <= nx < m and 0 <= ny < n: next_step = board[nx][ny] if next_step in node.children: dfs(nx, ny, path + next_step, node.children[next_step]) board[x][y] = path[-1] for i in range(m): for j in range(n): char = board[i][j] if char in trie.root.children: dfs(i, j, char, trie.root.children[char]) return result ``` ###### tags: `leetcode`