PracticeNeetCode ↗LeetCode ↗
Given an m × n grid of characters board and a list of strings words, return every word from the list that can be traced through a path of adjacent cells (up, down, left, right), using each cell at most once per word.
words so shared prefixes are only explored once.Time: O(m · n · 4^L) worst case, where L is the longest word's length — Space: O(N · L) for the trie, O(L) recursion depth
class TrieNode:
def __init__(self):
self.children: dict[str, "TrieNode"] = {}
self.word: str | None = None
def findWords(board: list[list[str]], words: list[str]) -> list[str]:
root = TrieNode()
for w in words:
node = root
for ch in w:
if ch not in node.children:
node.children[ch] = TrieNode()
node = node.children[ch]
node.word = w
rows, cols = len(board), len(board[0])
result = []
visited = set()
def dfs(r: int, c: int, node: TrieNode) -> None:
if (
r < 0 or c < 0 or r >= rows or c >= cols
or (r, c) in visited
or board[r][c] not in node.children
):
return
ch = board[r][c]
nxt = node.children[ch]
if nxt.word is not None:
result.append(nxt.word)
nxt.word = None
visited.add((r, c))
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
dfs(r + dr, c + dc, nxt)
visited.remove((r, c))
for r in range(rows):
for c in range(cols):
dfs(r, c, root)
return resultHow the solution above works, piece by piece.
dfs(r, c, node) tries to extend the current trie path with the letter at (r, c). It stops if the cell is off the board, already on the path, or the letter isn't a child of node.word = None so it isn't reported twice.Running it on the example board and words: