Skip to content
mlmentorship

Design Add and Search Words

Store words and support `.` as a wildcard that matches any one character.

Published · 11 min read ·Core ·Intermediate

30-second answer map

Visual first · depth when needed

A literal follows one child; a dot recursively tries each child until one full-length terminal path succeeds.

Preparing the visual…

ML breadth · active recall

Practice before you read

8 minutes. Explain the mechanism, why it works, when it fails, and one alternative.

How practice works

ML breadth · closed-book attempt

Design Add and Search Words

Explain the mechanism, why it works, when it fails, and one alternative.

08:00recommended time

Closing or reloading clears the scratchpad. Only score, weak rubric dimensions, attempt count, and retry date can be stored locally.

Store words and support . as a wildcard that matches any one character.

Start with the concrete trace below. It shows the state the algorithm must carry as it runs.

Problem trace

Design Add and Search Words: A literal follows one child; a dot recursively tries each child until one full-length terminal path succeeds.

Input and goalStore words and support `.` as a wildcard that matches any one character.
Store three terminal pathsbat, dad, and mad share root but have separate first-letter branches.
Shared-prefix trieOne node per shared prefix; double borders mark complete words.bdmaaatddcurrentrootbdmbadamabatdadmad

double border complete word

wordsbat,dad,madquery.adterminalbat,dad,mad

Recognize it
A stored-prefix query contains a symbol matching any one character.
Keep true
match(index,node) is true exactly when a terminal descendant matches the remaining suffix.
Reuse it
Branch recursion only at ambiguous symbols and preserve terminal semantics at exact query length.
Read it this way: bat, dad, and mad share root but have separate first-letter branches. Step through the frames to watch the state change. The last frame shows the answer or the stopping condition.

Pattern: Trie plus DFS when a wildcard appears.

Simple idea: Normal letters follow one child. A dot tries every child. The end marker still checks that the full word length matched.

class WordDictionary:
   def __init__(self) -> None:
      self.root: dict = {}

   def add_word(self, word: str) -> None:
      node = self.root
      for char in word:
         node = node.setdefault(char, {})
      node[None] = True

   def search(self, word: str) -> bool:
      def match(index: int, node: dict) -> bool:
         if index == len(word):
            return None in node
         if word[index] == ".":
            return any(match(index + 1, child) for key, child in node.items() if key)
         return word[index] in node and match(index + 1, node[word[index]])

      return match(0, self.root)

Cost: Adding takes time. A normal search takes . Many wildcards can make search exponential in the word length.