前缀树又称为字典树,单词查找树。其最大的优点为利用字符串的公共前缀极大的提高字符串的查询效率。如下图所示为“apple”,“app”,“apply” “pen”组成的前缀树结构
问题一:leetcod208实现前缀树
问题描述:
实现一个 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 构成的。
保证所有输入均为非空字符串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决思路:
由于题目中提到输入全为小写字母a-z,因此可以使用大小为26的数组充当hashmap的角色。结点的数据结构定义如下:
private static class Node{
Node[] next;
boolean isEnd;
public Node(){
isEnd = false;
next = new Node[26];
}
}
isEnd用于标识当前结点是否为一个单词终止结点。
实现代码如下:
class Trie {
private static class Node{
Node[] next;
boolean isEnd;
public Node(){
isEnd = false;
next = new Node[26];
}
}
Node root;
/** Initialize your data structure here. */
public Trie() {
root = new Node();
}
/** Inserts a word into the trie. */
public void insert(String word) {
Node temp = root;
for(int i = 0; i < word.length(); i++){
if(temp.next[word.charAt(i) - 'a'] == null){
temp.next[word.charAt(i) - 'a'] = new Node();
}
temp = temp.next[word.charAt(i) - 'a'];
if(i == word.length() - 1){
temp.isEnd = true;
}
}
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
Node temp = root;
for(int i = 0; i < word.length(); i++){
if(temp.next[word.charAt(i) - 'a'] == null){
return false;
}
temp = temp.next[word.charAt(i) - 'a'];
if(i == word.length() - 1){
return temp.isEnd;
}
}
return false;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
Node temp = root;
for(int i = 0; i < prefix.length(); i++){
if(temp.next[prefix.charAt(i) - 'a'] == null){
return false;
}
temp = temp.next[prefix.charAt(i) - 'a'];
}
return true;
}
}
一个最直接的应用:单词的添加和搜索
问题描述:
设计一个支持以下两种操作的数据结构:
void addWord(word)
bool search(word)
search(word) 可以搜索文字或正则表达式字符串,字符串只包含字母 . 或 a-z 。 . 可以表示任何一个字母。
示例:
addWord("bad")
addWord("dad")
addWord("mad")
search("pad") -> false
search("bad") -> true
search(".ad") -> true
search("b..") -> true
说明:
你可以假设所有单词都是由小写字母 a-z 组成的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-and-search-word-data-structure-design
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决思路:
插入操作同问题一中的插入相同,搜索操作由于加入了正则化‘.’表示任意一个字符,因此需要让‘.’充当任意字符在trie中查找,很明显使用dfs查找即可。
实现代码如下:
class WordDictionary {
private static class Node{
boolean isEnd;
Node[] next;
public Node(){
isEnd = false;
next = new Node[26];
}
}
Node root;
/** Initialize your data structure here. */
public WordDictionary() {
root = new Node();
}
/** Adds a word into the data structure. */
public void addWord(String word) {
Node cur = root;
for(int i = 0; i < word.length(); i++){
if(cur.next[word.charAt(i) - 'a'] == null){
cur.next[word.charAt(i) - 'a'] = new Node();
}
cur = cur.next[word.charAt(i) - 'a'];
if(i == word.length() - 1){
cur.isEnd = true;
}
}
}
/** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
public boolean search(String word) {
return search(word, root, 0);
}
public boolean search(String word, Node cur, int index){ //cur为index的前一个节点
if(index == word.length()){
return cur == null ? false : cur.isEnd;
}
if(word.charAt(index) != '.'){
if(cur.next[word.charAt(index) - 'a'] == null){
return false;
}
return search(word, cur.next[word.charAt(index) - 'a'], index+1);
}
for(int i = 0; i < 26; i++){
if(cur.next[i] != null){
if(search(word, cur.next[i], index + 1)){
return true;
}
}
}
return false;
}
}
后记:前缀树的应用还有很多例如自动补全,拼写检查,ip路由的最长前缀匹配,9宫格打字预测。