实现Trie结构,具有插入单词,查找完整单词,查找单词前缀的作用。
思路:
首先要说下什么是trie,比如在string中搜索pattern
在banana中搜索“ban", “ana”, "nab"这几个pattern,那么就需要一次一个pattern地搜,但是在pattern很多的时候复杂度就会是O(average pattern.length * pattern num*text.length)
trie就是把很多string pattern整合在一起,然后搜索的时候可以减掉pattern num这一项
比如ba和bb,组合成
因此在baabb中搜索ba和bb时,可以通过一个trie一次满足
如果在上述trie中再insert一个b,trie会变成
这时候说下search,search有full search和prefix search,就是完全相同,或者是否以pattern开头。如果是完全相同方式搜索,当搜索ba时,会走bab路径,这时候如何判断ba是一个完整的字符串,还是bab的一部分?就需要一个boolean值endOfWord来判断,endOfWord=true时,就知道a已经是子字符串的终点。
所以定义TrieNode结构,需要包含一个指向下一节点的TrieNode指针,和一个endOfWord的boolean值。因为可能有多个children,所以用Map来定义children。
class TrieNode{
Map<Character, TrieNode> children;
boolean endOfWord;
public TrieNode(){
children = new HashMap<>();
endOfWord = false;
}
}
插入操作时,先看当前字母在trie中是否存在,如果存在,走向它的下一节点,如果不存在,建立新的TrieNode。当走到最后一个字母时,endOfWord设为 true
public void insert(String word) {
char ch = 0;
TrieNode current = root;
TrieNode node;
for(int i = 0; i < word.length(); i++) {
ch = word.charAt(i);
node = current.children.get(ch);
if(node == null) {
node = new TrieNode();
current.children.put(ch, node);
}
current = node;
}
current.endOfWord = true;
}
新建一个Trie时,只需建立一个root和它的一个空children
private final TrieNode root;
public Trie() {
root = new TrieNode();
}
完全搜索和前缀搜索的区别只是走到最后一个字母时,看endOfWord是否为true
public boolean search(String word) {
char ch = 0;
TrieNode current = root;
TrieNode node;
for(int i = 0; i < word.length(); i++) {
ch = word.charAt(i);
node = current.children.get(ch);
if(node == null) {
return false;
}
current = node;
}
if(!current.endOfWord) {
return false;
}
return true;
}
public boolean startsWith(String prefix) {
char ch = 0;
TrieNode current = root;
TrieNode node;
for(int i = 0; i < prefix.length(); i++) {
ch = prefix.charAt(i);
node = current.children.get(ch);
if(node == null) {
return false;
}
current = node;
}
return true;
}
}
因为题目中说word和prefix只含有小写英文字母,那么就不需要用hashMap, 用一个长度为26的数组即可。
通过数组下标查找key.
class Trie {
Node root;
public Trie() {
root = new Node();
}
public void insert(String word) {
Node cur = root;
Node tmpNode;
for(int i = 0; i < word.length(); i++) {
int idx = word.charAt(i) - 'a';
tmpNode = cur.children[idx];
if(tmpNode == null) {
tmpNode = new Node();
cur.children[idx] = tmpNode;
}
cur = tmpNode;
}
cur.isEnd = true;
}
public boolean search(String word) {
Node cur = root;
Node tmpNode;
for(int i = 0; i < word.length(); i++) {
int idx = word.charAt(i) - 'a';
tmpNode = cur.children[idx];
if(tmpNode == null) return false;
cur = tmpNode;
}
if(!cur.isEnd) return false;
return true;
}
public boolean startsWith(String prefix) {
Node cur = root;
Node tmpNode;
for(int i = 0; i < prefix.length(); i++){
int idx = prefix.charAt(i) - 'a';
tmpNode = cur.children[idx];
if(tmpNode == null) return false;
cur = tmpNode;
}
return true;
}
}
class Node{
Node[] children;
boolean isEnd;
Node() {
children = new Node[26];
}
}