208. 實現 Trie (前綴樹)
定義
又稱單詞查找樹,Trie樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用於統計,排序和保存大量的字符串(但不僅限於字符串),所以經常被搜索引擎系統用於文本詞頻統計。它的優點是:利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高。
例如:
Trie存儲的是單詞,查詢的時間複雜度是O(w),w爲所查詢單詞的長度;如果使用樹結構進行存儲,查詢的時間複雜度爲O(logn);當存儲的單詞數量逐漸增多的情況下,樹結構查詢的時間複雜度是逐漸大於Trie的,而Trie的時間複雜度還是O(w),不會因爲存儲單詞的多少而發生變化。
侷限性
class Node{
public boolean isWord;// 是否爲單詞結尾
public TreeMap<Character, Node> next;// 存儲節點和字母 使用映射連接每個節點
}
最大的問題是空間!原本存儲一個單詞使用一個節點的空間,現在每個節點只能存儲一個字母,相比之前空間佔用成倍上升,解決方法詳見壓縮字典樹Compressed 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 構成的。
保證所有輸入均爲非空字符串。
Trie.java(字典樹)
import java.util.TreeMap;
//字典樹Trie
public class Trie {
private class Node {
public boolean isWord;// 是否爲單詞結尾
public TreeMap<Character, Node> next;// 存儲節點和字母 使用映射連接每個節點
public Node(boolean isWord) {
this.isWord = isWord;
next = new TreeMap<>();
}
public Node() {
// TODO Auto-generated constructor stub
this(false);
}
}
private Node root;// 根結點
private int size;// 存儲單詞個數
public Trie() {
// TODO Auto-generated constructor stub
root = new Node();
size = 0;
}
public int getSize() {
return size;
}
// 添加一個新的單詞
public void insert(String word) {
Node cur = root;
for (int i = 0; i < word.length(); i++) {// 遍歷單詞的字符
char c = word.charAt(i);
if (cur.next.get(c) == null)// 是否已經包含字符c
cur.next.put(c, new Node());// 添加
cur = cur.next.get(c);// 如果有,cur指向c
}
if (!cur.isWord) {// 如果這個單詞之前沒有
cur.isWord = true;// 單詞結束
size++;
}
}
// 查詢Trie中是否有單詞word
public boolean search(String word) {
Node cur = root;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (cur.next.get(c) == null)
return false;
cur = cur.next.get(c);
}
return cur.isWord;// 判斷cur.isWord是否爲true
}
// 查詢Trie中是否存在prefix爲前綴的單詞
public boolean startsWith(String prefix) {
Node cur = root;
for (int i = 0; i < prefix.length(); i++) {
char c = prefix.charAt(i);
if (cur.next.get(c) == null)
return false;
cur = cur.next.get(c);
}
return true;
}
}
Main.java(測試)
public class Main {
public static void main(String[] args) {
Trie t = new Trie();
Trie trie = new Trie();
trie.insert("apple");
System.out.println(trie.search("apple")); // 返回 true
System.out.println(trie.search("app")); // 返回 false
System.out.println(trie.startsWith("app")); // 返回 true
trie.insert("app");
System.out.println(trie.search("app") ); // 返回 true
}
}
測試結果