前綴樹及其應用

前綴樹又稱爲字典樹,單詞查找樹。其最大的優點爲利用字符串的公共前綴極大的提高字符串的查詢效率。如下圖所示爲“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宮格打字預測。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章