package com.interview.design.questions;
import com.interview.utils.ConsoleWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created_By: stefanie
* Date: 15-1-14
* Time: 上午9:34
*/
public class DZ22_Tries {
//Space: O(26^L) L is the average length of words
class TrieNode{
boolean isWord = false;
HashMap<Character, TrieNode> children = new HashMap();
}
TrieNode root = new TrieNode();
//Time: O(L) L is the length of the word
public void add(String word){
TrieNode current = root;
for(int i = 0; i < word.length(); i++){
char ch = word.charAt(i);
if(current.children.containsKey(ch)){
current = current.children.get(ch);
} else {
TrieNode node = new TrieNode();
current.children.put(ch, node);
current = node;
}
}
current.isWord = true;
}
//Time: O(L)
private TrieNode getNode(String str){
TrieNode current = root;
for(int i = 0; i < str.length(); i++){
char ch = str.charAt(i);
if(! current.children.containsKey(ch)) return null;
current = current.children.get(ch);
}
return current;
}
//Time: O(L)
public boolean isWord(String word){
TrieNode node = getNode(word);
return node != null && node.isWord;
}
//Time: O(L)
public boolean isPrefix(String prefix){
TrieNode node = getNode(prefix);
return node != null;
}
//Time: O(M), M words having this prefix. M < 26^(the max length - prefix length)
public List<String> words(String prefix){
List<String> words = new ArrayList();
TrieNode node = getNode(prefix);
visit(node, prefix, words);
return words;
}
private void visit(TrieNode node, String prefix, List<String> words){
if(node == null) return;
if(node.isWord) words.add(prefix);
for(Map.Entry<Character, TrieNode> child : node.children.entrySet()){
visit(child.getValue(), prefix + child.getKey(), words);
}
}
public List<String> getFuzzyWords(String word, int missingLetters){
List<String> words = new ArrayList();
getFuzzyWords(root, word, "", missingLetters, words);
return words;
}
private void getFuzzyWords(TrieNode node, String word, String prefix, int missingLetters, List<String> words){
if(word.length() == 0) {
if (node.isWord && !words.contains(prefix)) words.add(prefix);
if (missingLetters > 0) { //omit the following missingLetters chars in dict
for (Map.Entry<Character, TrieNode> child : node.children.entrySet())
getFuzzyWords(child.getValue(), word, prefix + child.getKey(), missingLetters - 1, words);
}
return;
}
char ch = word.charAt(0);
String suffix = word.substring(1);
if(node.children.containsKey(ch)) getFuzzyWords(node.children.get(ch), suffix, prefix + ch, missingLetters, words);
if(missingLetters > 0){
getFuzzyWords(node, suffix, prefix, missingLetters - 1, words); //omit the first char in word
for(Map.Entry<Character, TrieNode> child : node.children.entrySet()) //omit the first char in dict
getFuzzyWords(child.getValue(), word, prefix + child.getKey(), missingLetters - 1, words);
}
}
public static void main(String[] args){
DZ22_Tries tries = new DZ22_Tries();
tries.add("English");
tries.add("French");
tries.add("Frenchman");
tries.add("Engineer");
tries.add("Summer");
System.out.println(tries.isWord("French")); //true
System.out.println(tries.isWord("Fre")); //false
System.out.println(tries.isWord("Frencha")); //false
System.out.println(tries.isPrefix("Frech")); //false
System.out.println(tries.isPrefix("Fre")); //true
List<String> words = tries.words("En");
ConsoleWriter.printCollection(words); //English, Engineer
words = tries.words("Engl");
ConsoleWriter.printCollection(words); //English
ConsoleWriter.printCollection(tries.getFuzzyWords("Frencha", 1)); //French
ConsoleWriter.printCollection(tries.getFuzzyWords("Fresdncha", 5)); //French Frenchman
ConsoleWriter.printCollection(tries.getFuzzyWords("eEfnsglaissh", 5)); //English
ConsoleWriter.printCollection(tries.getFuzzyWords("ng", 5)); //English
}
}