Shubham Sourabhthe room · director's cutplain résumé
Room 04 · The Grind — Tries

Word Search II

HARD✓ CHIP-TIMEDLC #212 — FULL STATEMENT

The briefingthe full drill, in my own words

The drill: A letter grid and a list of candidate words — report every candidate that can actually be traced out by stepping to horizontally or vertically adjacent cells, never reusing a cell inside the same word.

A letter grid and a list of candidate words arrive together. For each candidate, the question is whether it can be traced by stepping to horizontally or vertically adjacent cells, one letter per step, never reusing a cell within that word's own path.

The output is the list of candidates that actually succeed — every word that can't be traced on the board is simply left out, and a word that appears twice in the candidate list should still only be reported once.

Different candidate words may reuse the very same cells on the board; the no-reuse rule only applies within a single word's own path, not across separate words.

  • grids stay modest, typically a few hundred cells
  • candidate words are generally short, well under twenty letters each
  • a single word's path never reuses the same cell twice
  • each qualifying candidate is reported once, even if listed multiple times
EX 01
board = ["race", "oats", "ring", "edym"] · words = ["race", "oats", "ring", "rore", "cast", "zzz"]
→ ["race", "oats", "ring", "rore"]
straight horizontal and vertical paths on a 4x4 grid, two candidates absent
EX 02
board = ["x"] · words = ["x", "y"]
→ ["x"]
single-cell board
EX 03
board = ["ab", "cd"] · words = ["abdc", "abc"]
→ ["abdc"]
a word using every cell exactly once via a turn, versus one that can't be formed at all

The hintstake only what you need

HINT 1 THE NUDGE

Running the single-word board search once per candidate re-walks the same grid from scratch every time — most of that work retraces paths that no candidate even starts with. What if every candidate's search could share its early steps?

HINT 2 THE STRUCTURE

Words with the same prefix should share the same walk down the board until they actually diverge — that's exactly the shape a trie stores, letter by letter.

HINT 3 ONE STEP FROM THE ANSWER

Merge all the candidate words into one trie first, then do a single backtracking scan of the board following trie edges instead of blind neighbors. Whenever the node you land on is marked as a complete word, record it and clear that mark so it's never recorded twice.

Coach's boardthe pattern, step by step

THE MERGED WALKPATTERN · TRIE-GUIDED BACKTRACKINGboard = ["an","xt"] · words = [an, ant, at]
a
n
x
t
STEP 1

Words an, ant, at merge into one trie: a branches to n (word 'an', continuing to t for 'ant') and to t (word 'at').

STEP 1 / 8 · ← → WORK TOO

The splitstwo paces, two languages

grind/word-search-ii.py — RACE PACE
LANG ▸
PACE ▸
class TrieNode:
    def __init__(self):
        self.children = {}
        self.word = None  # the full word, set only at a terminal node


class Solution:
    def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        root = TrieNode()
        for w in words:
            node = root
            for ch in w:
                node = node.children.setdefault(ch, TrieNode())
            node.word = w

        rows, cols = len(board), len(board[0])
        result = []

        def dfs(r: int, c: int, node: TrieNode) -> None:
            ch = board[r][c]
            child = node.children.get(ch)
            if child is None:
                return
            if child.word is not None:
                result.append(child.word)
                child.word = None  # never report the same word twice

            board[r][c] = "#"
            for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                nr, nc = r + dr, c + dc
                if 0 <= nr < rows and 0 <= nc < cols and board[nr][nc] != "#":
                    dfs(nr, nc, child)
            board[r][c] = ch

            if not child.children:
                del node.children[ch]  # dead branch, prune it for later scans

        for r in range(rows):
            for c in range(cols):
                dfs(r, c, root)

        return result
TIME O(M·N·4^L)SPACE O(Σ|WORDS|)PYTHON · RACE PACE · 42 LN

✓ CHIP-TIMEDALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED