1. 程式人生 > >前綴樹

前綴樹

for 存儲 icu etc 尋找 ins 單元 相同 輸入

前綴樹:前綴直白理解就是單詞的前綴。

前綴樹的每個結點都會初始化為有26個空指針(這是用數組來存儲子節點的一種方法),生成一顆前綴樹就是不斷插入單詞。

舉個栗子,對一棵空樹,插入單詞cat,根節點的子節點root->children[‘c‘ - ‘a‘]此時為空指針,就對其new出一個結點來,再對新結點插入字符‘a‘。

應用:尋找元素從頭開始的異同性

421. 數組中兩個數的最大異或值

212. 單詞搜索 II

先說單詞搜索這道題:

給定一個二維網格 board 和一個字典中的單詞列表 words,找出所有同時在二維網格和字典中出現的單詞。

單詞必須按照字母順序,通過相鄰的單元格內的字母構成,其中“相鄰”單元格是那些水平相鄰或垂直相鄰的單元格。同一個單元格內的字母在一個單詞中不允許被重復使用。

示例:

輸入: 
words = ["oath","pea","eat","rain"] and board =
[
  [‘o‘,‘a‘,‘a‘,‘n‘],
  [‘e‘,‘t‘,‘a‘,‘e‘],
  [‘i‘,‘h‘,‘k‘,‘r‘],
  [‘i‘,‘f‘,‘l‘,‘v‘]
]

輸出: ["eat","oath"]

說明:
你可以假設所有輸入都由小寫字母 a-z 組成。

提示:

    • 你需要優化回溯算法以通過更大數據量的測試。你能否早點停止回溯?
    • 如果當前單詞不存在於所有單詞的前綴中,則可以立即停止回溯。什麽樣的數據結構可以有效地執行這樣的操作?散列表是否可行?為什麽? 前綴樹如何?如果你想學習如何實現一個基本的前綴樹,請先查看這個問題: 實現Trie(前綴樹)

這道題折騰我好久....

首先用最笨的DFS,先把二維網絡的字符都記錄下來,比如‘a‘在哪些地方出現了。然後對待搜索的每個單詞,先看首字符有沒有在網格裏出現,出現了就以其為起點在網格裏慢慢搜。由於不能重復使用元素,就建了個set,每搜一個字符先判斷在set裏出現沒。這方法,看起來就很蠢...但一般的測試還能應付,後面的就超時了...

然後看提示,要避免搜不存在的前綴,這裏的意思是,如果網格搜索的時候碰到不是待搜索單詞的前綴,就可以不用搜了。

其次,用樹的好處是,如果有的單詞前綴相同,利用前綴樹一次搜過去就基本遍歷完了,但如果針對單個單詞一次次去DFS就很煩了。

class TrieNode {
public:
    TrieNode* children[26];
    string s;

    TrieNode() {
        s = "";
        for(int i = 0;i<26;++i) children[i] = NULL;
    }
    
};
    
class Solution {
public:
    TrieNode* root;
    void insert(string word){
        TrieNode* tmp = root;
        for(int i = 0;i<word.length();++i){
            int c = word[i] - a;
            if(!tmp->children[c]){
                tmp->children[c] = new TrieNode();
            }
            tmp = tmp->children[c];
        }
        tmp->s = word;
    } 
    
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        vector<string> res;
        int n = board.size();if(n == 0) return res;
        int m = board[0].size();if(m == 0) return res;
        
        root = new TrieNode();
        for(auto p:words) insert(p);
        
        for(int i = 0;i<n;++i){
            for(int j = 0;j<m;++j){
//                if(root->children[board[i][j] - ‘a‘]){
//                    DFS(board,root->children[board[i][j] - ‘a‘],i,j,res);
//                }
                DFS2(board,root,i,j,res);
            }
        }
        
        return res;
    }
    
    void DFS(vector<vector<char>>& board,TrieNode* tmp,int i,int j,vector<string>& res){
        if(tmp->s.length()){
            res.push_back(tmp->s);
            tmp->s.clear();
        }
        
        char c = board[i][j];
        
        board[i][j] = #;
        if(i>0 && board[i-1][j]!=# && tmp->children[board[i-1][j] - a]) DFS(board,tmp->children[board[i-1][j] - a],i-1,j,res);
        if(j>0 && board[i][j-1]!=# && tmp->children[board[i][j-1] - a]) DFS(board,tmp->children[board[i][j-1] - a],i,j-1,res);
        if(i+1<board.size() && board[i+1][j]!=# && tmp->children[board[i+1][j] - a]) DFS(board,tmp->children[board[i+1][j] - a],i+1,j,res);
        if(j+1<board[0].size() && board[i][j+1]!=# && tmp->children[board[i][j+1] - a]) DFS(board,tmp->children[board[i][j+1] - a],i,j+1,res);
        board[i][j] = c;
    }
    
    void DFS2(vector<vector<char>>& board,TrieNode* tmp,int i,int j,vector<string>& res){
        char c = board[i][j];
        if(c == # || !tmp->children[c - a]) return;
        
        tmp = tmp->children[c - a];
        if(tmp->s.length()){
            res.push_back(tmp->s);
            tmp->s.clear();
        }
        
        board[i][j] = #;
        if(i>0) DFS2(board,tmp,i-1,j,res);
        if(j>0) DFS2(board,tmp,i,j-1,res);
        if(i+1<board.size()) DFS2(board,tmp,i+1,j,res);
        if(j+1<board[0].size()) DFS2(board,tmp,i,j+1,res);
        board[i][j] = c;
    }
};

前綴樹