Question
Design a data structure that supports the following two operations:
void addWord(word) bool search(word)
search(word) can search a literal word or a regular expression string containing only letters a-z
or .
. A .
means it can represent any one letter.
For example:
addWord("bad") addWord("dad") addWord("mad") search("pad") -> false search("bad") -> true search(".ad") -> true search("b..") -> true
Note:
You may assume that all words are consist of lowercase letters a-z
.
Solution
This kind of problem (searching a String) can be solved by Trie.
We use DFS to implement search. Notice corner cases.
When we choose to implement it by recursion, think one step each time.
1 class TrieNode { 2 public char value; 3 public boolean isLeaf; 4 public HashMap<Character, TrieNode> children; 5 6 public TrieNode(char c) { 7 value = c; 8 children = new HashMap<Character, TrieNode>(); 9 isLeaf = false; 10 } 11 } 12 13 public class WordDictionary { 14 public TrieNode root; 15 16 public WordDictionary() { 17 root = new TrieNode('!'); 18 } 19 20 // Adds a word into the data structure. 21 public void addWord(String word) { 22 TrieNode currentNode = root; 23 for (int i = 0; i < word.length(); i++) { 24 char tmp = word.charAt(i); 25 HashMap<Character, TrieNode> children = currentNode.children; 26 TrieNode nextNode; 27 if (children.containsKey(tmp)) { 28 nextNode = children.get(tmp); 29 } else { 30 nextNode = new TrieNode(tmp); 31 children.put(tmp, nextNode); 32 } 33 currentNode = nextNode; 34 // Check whether it's the last character 35 if (i == word.length() - 1) 36 currentNode.isLeaf = true; 37 } 38 } 39 40 // Returns if the word is in the data structure. A word could 41 // contain the dot character '.' to represent any one letter. 42 public boolean search(String word) { 43 return dfsSearch(word, 0, root); 44 } 45 46 private boolean dfsSearch(String word, int index, TrieNode prevNode) { 47 // If prevNode is null but word has not been completely traversed, return fasle 48 if (prevNode == null) { 49 return false; 50 } 51 52 // If word has been completely traversed, check whether tree is at bottom 53 if (index == word.length()) { 54 return prevNode.isLeaf; 55 } 56 char target = word.charAt(index); 57 HashMap<Character, TrieNode> currentMap = prevNode.children; 58 59 if (target != '.') { 60 if (!currentMap.containsKey(target)) 61 return false; 62 else 63 return dfsSearch(word, index + 1, currentMap.get(target)); 64 } else { 65 boolean result = false; 66 for (Character key : currentMap.keySet()) { 67 if (dfsSearch(word, index + 1, currentMap.get(key))) { 68 result = true; 69 } 70 } 71 return result; 72 } 73 } 74 } 75 76 // Your WordDictionary object will be instantiated and called as such: 77 // WordDictionary wordDictionary = new WordDictionary(); 78 // wordDictionary.addWord("word"); 79 // wordDictionary.search("pattern");