Design Add and Search Words Data Structure
A trie whose search can branch on a '.' wildcard
This is the same trie as Implement Trie, plus one twist: a search query can contain '.', a wildcard matching any single letter. A literal character still walks one deterministic link, but a '.' forces the search to try every child at that position — branching, not walking — and stop at the first branch that leads to a match.
Details
Animated on: addWord("bad"), addWord("dad"), addWord("mad"), then search("pad"), search("bad"), search(".ad"), search("b..").
Problem:Design Add and Search Words Data StructureMedium
Pattern:Trie
A trie whose search can branch on a '.' wildcard
step 1 / 15
'b': no "b" node yet, so create it and step down.
1FUNCTION addWord(word):2 cur <- root3 FOR ch IN word:4 IF ch NOT IN cur.children: cur.children[ch] <- new node5 cur <- cur.children[ch]6 cur.end <- true7FUNCTION search(word): RETURN dfs(root, 0)8FUNCTION dfs(node, i):9 IF i = LENGTH(word): RETURN node.end10 IF word[i] != '.': RETURN (word[i] IN node.children) AND dfs(node.children[word[i]], i+1)11 FOR child IN node.children:12 IF dfs(child, i+1): RETURN true13 RETURN false
← / → step · space play · Home restart
Every step in words
Show all 15 steps
- 'b': no "b" node yet, so create it and step down.
- 'a': no "ba" node yet, so create it and step down.
- Last character 'd': create node "bad" and mark it END (double ring) — the path now spells a stored word, not just a prefix.
- addWord("dad"): walk/create root -> d -> da -> dad and mark "dad" END. Nodes already shared with an earlier word (like the "a" under a matching first letter) are reused, not duplicated.
- addWord("mad"): walk/create root -> m -> ma -> mad and mark "mad" END. Nodes already shared with an earlier word (like the "a" under a matching first letter) are reused, not duplicated.
- At node "root" the next character is literal 'p', and no such child exists (only b, d, m) — search("pad") returns false immediately.
- "bad" is literal, so walk it deterministically: "root" -> b -> ba -> bad, matching an existing chain the whole way.
- The query is exhausted on node "bad", whose END flag is set — search("bad") returns true.
- Position 0 is a wildcard: from node "root" try every child in turn — b, d, m.
- "ad" is literal, so walk it deterministically: "b" -> ba -> bad, matching an existing chain the whole way.
- The query is exhausted on node "bad", whose END flag is set — search(".ad") returns true.
- "b" is literal, so walk it deterministically: "root" -> b, matching an existing chain the whole way.
- Position 1 is a wildcard: from node "b" try every child in turn — a.
- Position 2 is a wildcard: from node "ba" try every child in turn — d.
- The query is exhausted on node "bad", whose END flag is set — search("b..") returns true.
Now solve it yourself
Watching is the first half. The second is writing it without the animation.