Coding Interview PatternsDesign Add and Search Words Data Structure
MediumTrie
Design Add and Search Words Data Structure
Explanation & Solution
Description
Design a data structure that supports adding new words and finding if a string matches any previously added string.
Implement the WordDictionary class:
WordDictionary()— Initializes the object.addWord(word)— Addswordto the data structure. It can be matched later.search(word)— Returnstrueif there is any string in the data structure that matchesword, orfalseotherwise.wordmay contain dots'.'where dots can be matched with any letter.
Input:operations = ["WordDictionary","addWord","addWord","addWord","search","search","search","search"], operands = [[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
0
WordDictionary
1
addWord
2
addWord
3
addWord
4
search
5
search
6
search
7
search
Output:[null,null,null,null,false,true,true,true]
0
null
1
null
2
null
3
null
4
false
5
true
6
true
7
true
Explanation: The WordDictionary is initialized, then "bad", "dad", and "mad" are added. Searching for "pad" returns false (not added). Searching for "bad" returns true (exact match). Searching for ".ad" returns true (matches "bad", "dad", or "mad"). Searching for "b.." returns true (matches "bad").
Constraints
1 <= word.length <= 25wordinaddWordconsists of lowercase English letterswordinsearchconsists of lowercase English letters or'.'- At most
10⁴calls will be made toaddWordandsearch
Approach
Trie pattern
1. Trie Node Structure
- Each node has a
childrenobject mapping characters to child nodes - Each node has an
isEndboolean to mark the end of a complete word - The
WordDictionaryitself acts as the root node
2. Adding a Word
- Start at the root and traverse character by character
- If the character does not exist in the current node's children, create a new node
- Move to the child node for each character
- Mark the final node as
isEnd = true
3. Searching with Wildcards
- Use DFS (depth-first search) to handle the
'.'wildcard - If the current character is
'.', try every child node recursively - If any child path leads to a match, return
true - If the current character is a regular letter, follow that specific child
4. Base Case
- When we reach the end of the search word (
index === word.length), check if the current node'sisEndistrue - This ensures we only match complete words, not just prefixes
Key Insight
- The
'.'wildcard transforms a simple trie lookup into a DFS problem — when we encounter a dot, we branch out and explore all possible children - Without wildcards, search is O(m). With wildcards, the worst case is O(26^m) but in practice the trie structure prunes most branches
Time
O(m) for `addWord`, **O(26^m)** worst case for `search` with wildcardsSpace
O(n * m) where n is the number of words and m is the average word length