1. 程式人生 > >[LeetCode] 208. Implement Trie (Prefix Tree) 實現字典樹(前綴樹)

[LeetCode] 208. Implement Trie (Prefix Tree) 實現字典樹(前綴樹)

分享 [] child height 查找樹 new t 實施 dex data

Implement a trie with insert, search, and startsWith methods.

Note:
You may assume that all inputs are consist of lowercase letters a-z.

實現一個數據結構:字典樹(前綴樹或單詞查找樹),具備insert, search, startsWith的功能。參考董的博客:數據結構之Trie樹

Trie樹,又稱字典樹,單詞查找樹或者前綴樹,是一種用於快速檢索的多叉樹結構,如英文字母的字典樹是一個26叉樹,數字的字典樹是一個10叉樹。Trie樹可以利用字符串的公共前綴來節約存儲空間。

Trie樹的基本性質可以歸納為:

(1)根節點不包含字符,除根節點以外每個節點只包含一個字符。

(2)從根節點到某一個節點,路徑上經過的字符連接起來,為該節點對應的字符串。

(3)每個節點的所有子節點包含的字符串不相同。

下圖是一個保存了8個鍵的trie結構,"A", "to", "tea", "ted", "ten", "i", "in", and "inn"

技術分享圖片

Trie樹復雜度:

(1)插入、查找的時間復雜度均為O(N),其中N為字符串長度。

(2) 空間復雜度是26^n級別的,非常龐大(可采用雙數組實現改善)。

實施方法:因為只用26個字母,所以可以用數組記錄,數組元素為TrieNode。

Java:

class TrieNode {
    private TrieNode[] children;
    public boolean hasWord;
    
    // Initialize your data structure here.
    public TrieNode() {
        children = new TrieNode[26];
        hasWord = false;
    }
    
    public void insert(String word, int index) {
        if (index == word.length()) {
            this.hasWord = true;
            return;
        }
        
        int pos = word.charAt(index) - ‘a‘;
        if (children[pos] == null) {
            children[pos] = new TrieNode();
        }
        children[pos].insert(word, index + 1);
    }
    
    public TrieNode find(String word, int index) {
        if (index == word.length()) {
            return this;
        }
        
        int pos = word.charAt(index) - ‘a‘;
        if (children[pos] == null) {
            return null;
        }
        return children[pos].find(word, index + 1);
    }
}

public class Trie {
    private TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    // Inserts a word into the trie.
    public void insert(String word) {
        root.insert(word, 0);
    }

    // Returns if the word is in the trie.
    public boolean search(String word) {
        TrieNode node = root.find(word, 0);
        return (node != null && node.hasWord);
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    public boolean startsWith(String prefix) {
        TrieNode node = root.find(prefix, 0);
        return node != null;
    }
} 

Python: Time: O(n), per operation, Space: O(1)

class TrieNode:
  def __init__(self):
    # Initialize your data structure here.
    self.childs = dict()
    self.isWord = False

class Trie:
  def __init__(self):
    self.root = TrieNode()

  # @param {string} word
  # @return {void}
  # Inserts a word into the trie.
  def insert(self, word):
    node = self.root
    for letter in word:
      child = node.childs.get(letter)
      if child is None:
        child = TrieNode()
        node.childs[letter] = child
      node = child
    node.isWord = True

  # @param {string} word
  # @return {boolean}
  # Returns if the word is in the trie.
  def search(self, word):
    node = self.root
    for letter in word:
      node = node.childs.get(letter)
      if node is None:
        return False
    return node.isWord

  # @param {string} prefix
  # @return {boolean}
  # Returns if there is any word in the trie
  # that starts with the given prefix.
  def startsWith(self, prefix):
    node = self.root
    for letter in prefix:
      node = node.childs.get(letter)
      if node is None:
        return False
    return True 

Python:

class TrieNode:
    def __init__(self):
        self.is_string = False
        self.leaves = {}
        

class Trie:

    def __init__(self):
        self.root = TrieNode()

    def insert(self, word):
        cur = self.root
        for c in word:
            if not c in cur.leaves:
                cur.leaves[c] = TrieNode()
            cur = cur.leaves[c]
        cur.is_string = True

    def search(self, word):
        node = self.childSearch(word)
        if node:
            return node.is_string
        return False        

    def startsWith(self, prefix):
        return self.childSearch(prefix) is not None

    def childSearch(self, word):
        cur = self.root
        for c in word:
            if c in cur.leaves:
                cur = cur.leaves[c]
            else:
                return None
        return cur

C++:

class TrieNode {
public:
    // Initialize your data structure here.
    TrieNode() : is_string(false) {
        
    }
    bool is_string;
    unordered_map<char, TrieNode *> leaves;
};

class Trie {
public:
    Trie() {
        root_ = new TrieNode();
    }

    void insert(string word) {
        auto *cur = root_;
        for (const auto& c : word) {
            if (!cur->leaves.count(c)) {
                cur->leaves[c] = new TrieNode();
            }
            cur = cur->leaves[c];
        }
        cur->is_string = true;
    }

    bool search(string word) {
        auto *node = childSearch(word);
        if (node) {
            return node->is_string;
        }
        return false;   
    }

    bool startsWith(string prefix) {
        return childSearch(prefix);
    }

    TrieNode *childSearch(const string& word) {
        auto *cur = root_;
        for (const auto& c : word) {
            if (cur->leaves.count(c)) {
                cur = cur->leaves[c];
            } else {
                return nullptr;
            }
        }
        return cur;
    }

private:
    TrieNode *root_;
};

 

  

[LeetCode] 208. Implement Trie (Prefix Tree) 實現字典樹(前綴樹)