字典樹 (Trie Tree)


字典樹(Trie Tree):

又稱單詞查找樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用於統計,排序和保存大量的字符串(但不僅限於字符串),所以經常被搜索引擎系統用於文本詞頻統計。它的優點是:利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高。

Trie Tree 的性質:

根節點不包含字符,除根節點外每一個節點都只包含一個字符; 從根節點到某一節點,路徑上經過的字符連接起來,為該節點對應的字符串; 每個節點的所有子節點包含的字符都不相同。

下面是字典樹的樹形結構圖示(圖源來自 Leetcode 題解討論區):

實現

這是 leetcode 題目:208. 實現 Trie (前綴樹)

節點

使用指針數組 links[26] 去記錄下一個字符,isEnd 表示該節點是否為葉子節點,同時也表示某次遍歷是否找到一個完整的單詞

class TrieNode {
private:
    vector<TrieNode*> links;
    bool isEnd;
public:
    TrieNode(){ isEnd = false; links.resize(26, nullptr); }
    bool containsKey(char c) { return links[c - 'a'] != nullptr; }
    void put(char c) { links[c - 'a'] = new TrieNode(); }
    TrieNode* get(char c) { return links[c - 'a']; }
    void setEnd() { isEnd = true; }
    bool getEnd() { return isEnd; }
};

字典樹

class Trie {
private:
    TrieNode *root;
public:
    Trie() { root = new TrieNode(); }
    void insert(string word)
    {
        auto cur = root;
        for (char c: word)
        {
            if (!cur->containsKey(c))
                cur->put(c);
            cur = cur->get(c);
        }
        cur->setEnd();
    }

    bool search(string word)
    {
        auto cur = root;
        for (char c: word)
        {
            if (!cur->containsKey(c))
                return false;
            else
                cur = cur->get(c);
        }
        return cur->getEnd();
    }

    bool startsWith(string prefix)
    {
        auto cur = root;
        for (char c: prefix)
        {
            if (!cur->containsKey(c))
                return false;
            else
                cur = cur->get(c);
        }
        return true;
    }
};

應用

單詞搜索 II

題目:212. 單詞搜索 II

解題思路

源於題解

將所有的 words 建立字典樹,然后對於 board 的每一個位置 (i,j) 進行 DFS。

代碼實現

struct TrieNode
{
    vector<TrieNode *> links;
    bool isend;
    string word;
    TrieNode() : isend(false), word("") { links.resize(26, nullptr); }
    bool contains(char c) { return links[c - 'a'] != nullptr; }
    void put(char c) { links[c - 'a'] = new TrieNode(); }
    TrieNode *get(char c) { return links[c - 'a']; }
};
class Solution
{
public:
    TrieNode *root = new TrieNode();
    vector<string> result;
    int row, col;
    vector<string> findWords(vector<vector<char>> &board, vector<string> &words)
    {
        if (board.size() == 0 || board[0].size() == 0)
            return result;
        buildTrieTree(words);
        row = board.size();
        col = board[0].size();
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                dfs(board, root, i, j);
            }
        }
        return result;
    }

    void dfs(vector<vector<char>> &board, TrieNode *p, int x, int y)
    {
        char ch = board[x][y];
        if (ch == '.' || !p->contains(ch))
            return;
        p = p->get(ch);
        if (p->isend && p->word != "")
        {
            result.push_back(p->word);
            // 防止重復添加
            p->word = "";
        }

        board[x][y] = '.';
        if (x - 1 >= 0)  dfs(board, p, x - 1, y);
        if (x + 1 < row) dfs(board, p, x + 1, y);
        if (y + 1 < col) dfs(board, p, x, y + 1);
        if (y - 1 >= 0)  dfs(board, p, x, y - 1);
        board[x][y] = ch;
    }

    void buildTrieTree(vector<string> &vs)
    {
        for (auto &x : vs)
        {
            auto cur = root;
            for (char c : x)
            {
                if (!cur->contains(c))
                    cur->put(c);
                cur = cur->get(c);
            }
            cur->isend = true, cur->word = x;
        }
    }
};

添加與搜索單詞

題目:211. 添加與搜索單詞 - 數據結構設計

遞歸搜索。

struct TrieNode
{
    vector<TrieNode *> links;
    bool isend;
    TrieNode() : isend(false) { links.resize(26, nullptr); }
    bool contains(char c) { return (links[c - 'a'] != nullptr); }
    void put(char c) { links[c - 'a'] = new TrieNode(); }
    TrieNode *get(char c) { return links[c - 'a']; }
};
class WordDictionary
{
public:
    TrieNode *root;
    /** Initialize your data structure here. */
    WordDictionary()
    {
        root = new TrieNode();
    }

    /** Adds a word into the data structure. */
    void addWord(string word)
    {
        auto cur = root;
        for (char c : word)
        {
            if (!cur->contains(c))
                cur->put(c);
            cur = cur->get(c);
        }
        cur->isend = true;
    }

    /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
    bool search(string word)
    {
        return innerSearch(root, word);
    }

    bool innerSearch(TrieNode *p, string word)
    {
        if (p == nullptr)
            return false;
        if (word.length() == 0)
            return p->isend;
        auto cur = p;
        int len = word.length();
        for (int i = 0; i < len; i++)
        {
            char c = word[i];
            if (c == '.')
            {
                for (auto x : cur->links)
                {
                    if (x != nullptr && innerSearch(x, word.substr(i + 1)))
                        return true;
                }
                return false;
            }
            else
            {
                if (!cur->contains(c))
                    return false;
                else
                    // return innerSearch(cur->get(c), word.substr(i + 1));
                    cur = cur->get(c);
            }
        }
        return cur->isend;
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM