↓快轉到主要內容
  1. LeetCode/

LeetCode 212: Word Search II

·1 分鐘· ·
LeetCode Hard Trie Backtracking Matrix
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-10-16

  • 提交紀錄:Accepted(一次通過)

解題思路
#

LC 79 Word Search 是找一個單字。這題有最多 3 * 10^4 個單字,每個單字各做一次網格搜尋太慢。

做法是把所有單字建成一棵 Trie,在網格上 DFS 的同時在 Trie 上往下走:

  • 下一格的字母不在 Trie 目前節點的子節點裡,就不用走。
  • 走到有結尾標記的節點,就找到一個單字。

兩個剪枝讓它夠快:

  1. 找到單字後把結尾標記移除:同一個單字不會被加兩次。
  2. 子樹空了就把節點從父節點刪掉:之後的 DFS 不會再走進已經沒有單字的分支。

我的解法
#

class Solution:
    def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        root = {}
        for w in words:
            node = root
            for ch in w:
                node = node.setdefault(ch, {})
            node["$"] = w

        m, n = len(board), len(board[0])
        res = []

        def dfs(r: int, c: int, parent: dict) -> None:
            ch = board[r][c]
            node = parent[ch]
            if "$" in node:
                res.append(node.pop("$"))
            board[r][c] = "#"
            for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                nr, nc = r + dr, c + dc
                if 0 <= nr < m and 0 <= nc < n and board[nr][nc] in node:
                    dfs(nr, nc, node)
            board[r][c] = ch
            if not node:
                parent.pop(ch)

        for r in range(m):
            for c in range(n):
                if board[r][c] in root:
                    dfs(r, c, root)
        return res

"#" 不會是任何 Trie 節點的 key,所以 board[nr][nc] in node 也順便擋掉了走過的格子。

複雜度
#

時間最壞 O(m n · 4 · 3^(L-1)),L 是單字最長長度(10):每個起點往下最多 L 層,除了第一步每步最多 3 個方向。剪枝讓實際上快很多。空間 O(所有單字總長度)。

要特別避免的錯誤
#

  • 每個單字各自做一次 Word Search。
  • 找到單字後沒有移除結尾標記,答案出現重複。
  • DFS 回來時沒有把格子還原。

面試口說整理
#

單字很多,所以我先把它們建成 Trie,在網格上 DFS 時同步沿著 Trie 往下走,下一格的字母不在目前節點的子節點裡就不走。走到結尾標記就把單字加入答案並移除標記,避免重複;DFS 回來時如果節點已經空了,就從父節點刪掉,之後不會再走進沒有單字的分支。

相關文章

LeetCode 980: Unique Paths III
·1 分鐘
LeetCode Hard Backtracking Matrix Dfs
LeetCode 980 解題筆記:網格回溯,原地標記走過的格子,到終點時檢查是否走過所有空格
LeetCode 2416: Sum of Prefix Scores of Strings
·1 分鐘
LeetCode Hard Trie String Counting
LeetCode 2416 解題筆記:Trie 每個節點記錄經過的單字數,單字的答案就是沿路計數的總和
LeetCode 773: Sliding Puzzle
·1 分鐘
LeetCode Hard Breadth-First-Search Dynamic-Programming Memoization Matrix
LeetCode 773 解題筆記:盤面只有 6! = 720 種,把盤面攤平成字串當 BFS 的狀態,0 跟相鄰格交換就是下一個狀態
LeetCode 864: Shortest Path to Get All Keys
·2 分鐘
LeetCode Hard Bfs Bit-Manipulation Matrix
LeetCode 864 解題筆記:BFS 的狀態是 (位置, 拿到的鑰匙遮罩),同一格拿著不同鑰匙是不同的節點
LeetCode 2328: Number of Increasing Paths in a Grid
·2 分鐘
LeetCode Hard Dynamic-Programming Grid-Dp Memoization Topological-Sort Matrix
LeetCode 2328 解題筆記:嚴格遞增所以沒有環;dp[cell] = 1 + Σ dp[比它大的鄰居],依值由大到小處理(或記憶化 DFS),全部加起來
LeetCode 1178: Number of Valid Words for Each Puzzle
·1 分鐘
LeetCode Hard Bit-Manipulation Hash-Map Trie
LeetCode 1178 解題筆記:單字只在乎用了哪些字母,轉成 26-bit 遮罩計數,再枚舉謎題遮罩的所有子集合