#211 Design Add and Search Words Data Structure
frequently reported atByteDance / TikTokAmazonAppleMicrosoftMetaGoogle
the problem
In plain words
Design WordDictionary with addWord(word) and search(pattern), where the pattern may contain . meaning "any one letter". Return whether some added word matches.
in addWord("bad"), addWord("dad"), addWord("mad"), search("pad"), search("bad"), search(".ad"), search("b..")
out null, null, null, false, true, true, true
- 1 ≤ word.length ≤ 25
- addWord: lowercase letters; search: lowercase letters or '.'
- At most 2 dots per search query
- At most 10⁴ calls
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
Design: implement every operation. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternTrie (prefix tree)
A normal letter has exactly one child to follow. A dot means "try every child" — so search is a DFS on the trie that only branches at the dots.
solutions
From brute force to optimal
Store every word; on search, compare the pattern with each same-length word, letting '.' match anything.
- addWord → list.add(word).
- search → for each word of equal length, compare char by char (dot = wildcard).
Every search may compare against all N words of length L.
The stored words.
class WordDictionaryList { private final List<String> words = new ArrayList<>(); public void addWord(String word) { words.add(word); } public boolean search(String pattern) { for (String w : words) { if (matches(w, pattern)) return true; } return false; } private boolean matches(String word, String pattern) { if (word.length() != pattern.length()) return false; for (int i = 0; i < word.length(); i++) { char p = pattern.charAt(i); if (p != '.' && p != word.charAt(i)) return false; } return true; }}Insert words into a trie. Search recursively: a letter follows one child, a dot tries all non-null children.
- dfs(pattern, i, node): if i == length → return node.isEnd.
- If pattern[i] is '.', return true if any child's dfs(i+1) succeeds.
- Otherwise follow the single child for that letter (false if missing).
Each dot can fan out to at most 26 children; with k ≤ 2 that is at most 676 paths — and never more than the nodes in the trie.
Nodes for all letters; the DFS is at most L deep.
class WordDictionary { private static class Node { Node[] children = new Node[26]; boolean isEnd; } private final Node root = new Node(); public void addWord(String word) { Node cur = root; for (char ch : word.toCharArray()) { int i = ch - 'a'; if (cur.children[i] == null) cur.children[i] = new Node(); cur = cur.children[i]; } cur.isEnd = true; } public boolean search(String pattern) { return dfs(pattern, 0, root); } private boolean dfs(String pattern, int i, Node node) { if (i == pattern.length()) return node.isEnd; // used every character char ch = pattern.charAt(i); if (ch == '.') { // wildcard: try every child for (Node child : node.children) { if (child != null && dfs(pattern, i + 1, child)) return true; } return false; // no child led to a word } Node next = node.children[ch - 'a']; // normal letter: one path only return next != null && dfs(pattern, i + 1, next); }}Dry run
in the room
How to say it in the interview
talk track
- Start from LC 208 — this is the same trie; only search changes.
- Say: "letters don't branch, dots do", then write the recursive helper with the index i.
- Mention the worst case explicitly (all dots) and that the constraint caps dots at 2.
traps
- Returning true when the pattern is used up without checking
isEnd. - Returning the result of the first child for '.' instead of continuing when it's false.
what they ask next
Follow-ups
What if '*' (any sequence) were allowed?
At '*' you either skip it (i+1, same node) or consume one letter (i, child) — it becomes a DP/DFS over (i, node) pairs; memoize to stay polynomial.
before you submit
Edge cases to test
- A pattern of only dots ("...") → true if any word has exactly that length.
- A dot whose first child fails must keep trying the other children.
- A pattern that matches only a prefix of a word → false (check isEnd).
practise next
Similar problems
- #208Implement Trie (Prefix Tree)Mediumin Tries
- #212Word Search IIHardin Tries
- #79Word SearchMediumin Backtracking