Trie
树模板
本质上是个多叉树
单个节点
class TrieNode {
public boolean isEnd;
public TrieNode[] next;
public TrieNode() {
isEnd = false;
next = new TrieNode[26];
}
}
isEnd
记录当前字符是否为某个字符串的最后一个字符
当遍历到某个isEnd==true
的节点时 表明该路径到当前节点位置为止的字符依次排列 所得字串是记录过的
next
数组记录当前字符是否存在 且用于存放孩子节点
记alpha
为当前字符 令i = alpha - 'a'
若next[i] == null
表明“在已经遍历了某个前缀的前提下 没有以alpha
字符继续的字串”
插入操作
遍历字符串每个字符
Trie
树按照当前字符切换到对应的next[i]
节点
若next[i]==null
则新建一个子节点 并继续下渗
直到记录完所有字符 把最后一个节点的isEnd
记录为true
public void insert(String word) {
TrieNode cur = root;
for (int i = 0; i < word.length(); i++) {
int idx = word.charAt(i) - 'a';
if (cur.next[idx] == null) cur.next[idx] = new TrieNode();
cur = cur.next[idx];
}
cur.isEnd = true;
}
查询操作
同样都是从根节点开始 按字符下渗
如果遇到“字符串还没遍历完而没有对应的子节点”时 未记录过该字串
如果“字符串以正常遍历完” 还要判断isEnd
是否为true
因为可能记录过某个以当前字串为前缀的字符串
public boolean search(String word) {
TrieNode cur = root;
for (int i = 0; i < word.length(); i++) {
int idx = word.charAt(i) - 'a';
if (cur.next[idx] == null) return false;
cur = cur.next[idx];
}
return cur.isEnd;
}
查询是否有以某前缀开始的字串
查询前缀类似查询字串 但不需要判断最终是否满足isEnd == true
public boolean startsWith(String prefix) {
TrieNode cur = root;
for (int i = 0; i < prefix.length(); i++) {
int idx = prefix.charAt(i) - 'a';
if (cur.next[idx] == null) return false;
cur = cur.next[idx];
}
return true;
}
完整代码
class Trie {
class TrieNode {
public boolean isEnd;
public TrieNode[] next;
public TrieNode() {
isEnd = false;
next = new TrieNode[26];
}
}
private TrieNode root;
/** Initialize your data structure here. */
public Trie() {
root = new TrieNode();
}
/** Inserts a word into the trie. */
public void insert(String word) {
TrieNode cur = root;
for (int i = 0; i < word.length(); i++) {
int idx = word.charAt(i) - 'a';
if (cur.next[idx] == null) cur.next[idx] = new TrieNode();
cur = cur.next[idx];
}
cur.isEnd = true;
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
TrieNode cur = root;
for (int i = 0; i < word.length(); i++) {
int idx = word.charAt(i) - 'a';
if (cur.next[idx] == null) return false;
cur = cur.next[idx];
}
return cur.isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
TrieNode cur = root;
for (int i = 0; i < prefix.length(); i++) {
int idx = prefix.charAt(i) - 'a';
if (cur.next[idx] == null) return false;
cur = cur.next[idx];
}
return true;
}
}
/**
* 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);
*/
发现查询子节点的操作很频繁 代码可以复用
修改完
class Trie {
class TrieNode {
public boolean isEnd;
public TrieNode[] next;
public TrieNode() {
isEnd = false;
next = new TrieNode[26];
}
}
private TrieNode root;
private TrieNode find(String str, boolean isInsert) {
TrieNode cur = root;
for (int i = 0; i < str.length(); i++) {
int index = str.charAt(i) - 'a';
if (cur.next[index] == null) {
if (isInsert) cur.next[index] = new TrieNode();
else return null;
}
cur = cur.next[index];
}
return cur;
}
/** Initialize your data structure here. */
public Trie() {
root = new TrieNode();
}
/** Inserts a word into the trie. */
public void insert(String word) {
find(word, true).isEnd = true;
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
TrieNode node = find(word, false);
return node != null && node.isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
return find(prefix, false) != null;
}
}
/**
* 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);
*/