208. 实现 Trie (前缀树)
题目描述
实现一个 Trie (前缀树),包含 insert
, search
, 和 startsWith
这三个操作。
示例:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // 返回 true
trie.search("app"); // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");
trie.search("app"); // 返回 true
说明:
a-z
构成的。第一种:R向单词查找树,每个节点都含有R个链接,对应着每个可能出现的字符,优点在于查找和插入的效率很高,与单词的长度成正比。缺点是空间消耗大。
/**
* @author yuan
* @date 2019/1/23
* @description R向单词查找树
*/
public class Trie {
private Node root;
private static int R = 26;
private class Node{
Node[] next = new Node[R];
char c;
boolean isWordEnd = false;
}
/** Initialize your data structure here. */
public Trie() {
}
/** Inserts a word into the trie. */
public void insert(String word) {
root = insert(root, word, 0);
}
private Node insert(Node x, String word, int d) {
if (x == null) {
x = new Node();
}
if (d == word.length()) {
x.isWordEnd = true;
return x;
}
char c = word.charAt(d);
x.next[c - 'a'] = insert(x.next[c - 'a'], word, d + 1);
return x;
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
Node x = search(root, word, 0);
if (x == null) {
return false;
}
return x.isWordEnd;
}
private Node search(Node x, String word, int d) {
if (x == null) {
return null;
}
if (d == word.length()) {
return x;
}
char c = word.charAt(d);
return search(x.next[c - 'a'], word, d + 1);
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
Node x = search(root, prefix, 0);
return x != null;
}
}
第二种:三向单词查找树,每个节点只有3个链接,所需空间远小于单词查找树。
三向单词查找树适用于查找键的不规则形。
比如有256个字符,R向单词树需要256向分支,需要巨大的开销,而三向单词查找树就不必担心这个问题。
/**
* @author yuan
* @date 2019/2/22
* @description 三向单词查找树
*/
public class Trie {
private Node root;
private class Node{
/**
* 字符
*/
char c;
/**
* 左中右子三向单词查找树
*/
Node left,mid, right;
boolean isWordEnd = false;
}
/** Initialize your data structure here. */
public Trie() {
}
public boolean search(String word) {
Node x = search(root, word, 0);
if (x == null) {
return false;
}
return x.isWordEnd;
}
private Node search(Node x, String word, int d) {
if (x == null) {
return null;
}
char c = word.charAt(d);
if (c < x.c) {
return search(x.left, word, d);
} else if (c > x.c) {
return search(x.right, word, d);
} else if (d < word.length() - 1) {
return search(x.mid, word, d + 1);
}
return x;
}
public void insert(String word) {
root = insert(root, word, 0);
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
Node x = search(root, prefix, 0);
return x != null;
}
private Node insert(Node x, String word, int d) {
char c = word.charAt(d);
if (x == null) {
x = new Node();
x.c = c;
}
if (c < x.c) {
x.left = insert(x.left, word, d);
} else if (c > x.c) {
x.right = insert(x.right, word, d);
} else if (d < word.length() - 1) {
x.mid = insert(x.mid, word, d + 1);
} else {
// 此时d = word.length - 1,到了单词的尾部
x.isWordEnd = true;
}
return x;
}
}