Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。
实现 Trie (前缀树)
https://leetcode-cn.com/problems/implement-trie-prefix-tree/
二叉树的每个节点存放两个指针,left指向左子树的头结点,right指向了右子树的头结点,这两个指针都为Node类型;
相对于二叉树,前缀树的节点也要存指针,指向其他子节点。那么对于这种类型的指针该如何设计呢,如果是要设计与字符串相关的前缀树(假设字符的范围为a-z),Node类中只需要维护一个指针数组,大小为26(对应26个英文字母),该数组也是Node类型,用来子节点的指针,很明显,前缀树是一个多叉树。
除了指针外,还要维护一个类型为boolean的变量,来判断节点是否为叶子节点。
那么对于前缀树的insert方法来说,不需要真正的插入字符串每个字符的值,只需要在每个节点中将字符所对应下标的位置上插入一个新的节点,就可以表示存在该字符,在前缀树表示的字符串最后的一个字符中,要将isLeaf变量设为true,表示字符串到此结束。
对于search方法来说,逐一判断前缀树中是否存在字符串的所有字符即可,如果前缀树中所对应字符串指定字符的节点为null,那么表示不存在该字符串,直到判断字符串的最后一个字符,并判断isLeaf是否为true。(表示字符串结束)
对于startsWith方法来说,逐一判断前缀树中是否存在字符串的所有字符即可,如果前缀树中所对应字符串指定字符的节点为null,那么表示不存在该字符串,直到判断字符串的最后一个字符即可。无需判断isLeaf。
class Trie {
private class Node{
Node[] childs = new Node[26];
boolean isLeaf;
}
private Node root = new Node();
/** Initialize your data structure here. */
public Trie() {}
/** Inserts a word into the trie. */
public void insert(String word) {
insert(word,root);
}
private void insert(String word,Node node) {
if(node == null) return;
if(word.length() == 0) {
node.isLeaf = true;
return;
}
int index = findCharIndex(word.charAt(0));
if(node.childs[index] == null)
node.childs[index] = new Node();
insert(word.substring(1),node.childs[index]);
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
return search(word,root);
}
private boolean search(String word,Node node) {
if(node == null) return false;
if(word.length() == 0) return node.isLeaf;
int index = findCharIndex(word.charAt(0));
return search(word.substring(1),node.childs[index]);
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
return startsWith(prefix,root);
}
private boolean startsWith(String prefix,Node node) {
if(node == null) return false;
if(prefix.length() == 0) return true;
int index = findCharIndex(prefix.charAt(0));
return startsWith(prefix.substring(1),node.childs[index]);
}
//找到指定字符在节点中的index
private int findCharIndex(char c) {
return c - 'a';
}
}
/**
* Your Trie object will be instantiated and called as such:
* Trie obj = new Trie();
* obj.insert(word);
* boolean param_2 = obj.search(word);
* boolean param_3 = obj.startsWith(prefix);
*/
键值映射
https://leetcode-cn.com/problems/map-sum-pairs/
思路和上面差不多,Node节点中维护一个值val
class MapSum {
private class Node {
Node[] childs = new Node[26];
int val;
}
private Node root = new Node();
/** Initialize your data structure here. */
public MapSum() {
}
public void insert(String key, int val) {
insert(key,val,root);
}
private void insert(String key,int val,Node node) {
if(node == null) return;
if(key.length() == 0) {
node.val = val;
return;
}
int index = findCharIndex(key.charAt(0));
if(node.childs[index] == null) //一定要加这个判断,否则会将旧值覆盖
node.childs[index] = new Node();
insert(key.substring(1),val,node.childs[index]);
}
private int findCharIndex(char c) {
return c - 'a';
}
public int sum(String prefix) {
return sum(prefix,root);
}
private int sum(String prefix, Node node) {
if (node == null) return 0;
if (prefix.length() != 0) {
int index = findCharIndex(prefix.charAt(0));
return sum(prefix.substring(1), node.childs[index]);
}
int sum = node.val;
for (Node child : node.childs) {
sum += sum(prefix, child);
}
return sum;
}
}