zoukankan      html  css  js  c++  java
  • (Trie树)leetcode208: Implement Trie,79:Word Search,DFS与BFS(python实现),212:Word Search2

    前缀树:查找字符串或其前缀。

    一)数组实现,每个结点初始化有26个子结点,插入结点时,将该字母对应索引上创建结点。

    class TrieNode{
    public:
        TrieNode* child[26];
        bool isWord;
        //构造函数初始化列表
        TrieNode() : isWord(false){
            for(auto& a: child)
                a = nullptr;
        }
        ~TrieNode(){
            delete[] child;
        }
    };
    
    class Trie {
    private:
        TrieNode* root;
        
    public:
        /** Initialize your data structure here. */
        Trie() {
            root = new TrieNode();
        }
        
        /** Inserts a word into the trie. */
        void insert(string word) {
            TrieNode* p = root;
            for(char a: word){
                int i = a - 'a';
                if(!p->child[i])
                    //若某一字母对应索引的结点不存在
                    p->child[i] = new TrieNode();
                p = p->child[i];
            }
            p->isWord = true;
        }
        
        /** Returns if the word is in the trie. */
        bool search(string word) {
            TrieNode* p = root;
            for(char a:word){
                int i = a - 'a';
                if(!p->child[i])
                    return false;
                p = p->child[i];
            }
            return p->isWord;
        }
        
        /** Returns if there is any word in the trie that starts with the given prefix. */
        bool startsWith(string prefix) {
            TrieNode* p = root;
            for(char a: prefix){
                int i = a - 'a';
                if(!p->child[i])
                    return false;
                p = p->child[i];
            }
            return true;
        }
    };
    
    /**
     * Your Trie object will be instantiated and called as such:
     * Trie* obj = new Trie();
     * obj->insert(word);
     * bool param_2 = obj->search(word);
     * bool param_3 = obj->startsWith(prefix);
     */
    class TrieNode{
    public:
        vector<TrieNode*> child;
        bool isWord;
        //构造函数初始化列表
        TrieNode() : isWord(false), child(26, nullptr){}
        ~TrieNode(){
            for(auto& c:child)
                delete c;
        }
    };
    
    class Trie {
    private:
        TrieNode* root;
        
    public:
        /** Initialize your data structure here. */
        Trie() {
            root = new TrieNode();
        }
        
        /** Inserts a word into the trie. */
        void insert(string word) {
            TrieNode* p = root;
            for(char a: word){
                int i = a - 'a';
                if(!p->child[i])
                    //若某一字母对应索引的结点不存在
                    p->child[i] = new TrieNode();
                p = p->child[i];
            }
            p->isWord = true;
        }
        
        /** Returns if the word is in the trie. */
        bool search(string word) {
            TrieNode* p = root;
            for(char a:word){
                int i = a - 'a';
                if(!p->child[i])
                    return false;
                p = p->child[i];
            }
            return p->isWord;
        }
        
        /** Returns if there is any word in the trie that starts with the given prefix. */
        bool startsWith(string prefix) {
            TrieNode* p = root;
            for(char a: prefix){
                int i = a - 'a';
                if(!p->child[i])
                    return false;
                p = p->child[i];
            }
            return true;
        }
    };
    
    /**
    二)vector容器实现,注意下构造函数和析构函数与数组的写法有差异。 * Your Trie object will be instantiated and called as such: * Trie* obj = new Trie(); * obj->insert(word); * bool param_2 = obj->search(word); * bool param_3 = obj->startsWith(prefix);
    */

    注意:同一个字符不能使用多次,即不能往回走。

    思路:深度优先搜索,枚举每一个格子,将它作为根结点,来向上,向左,向右,向下寻找和word相同的字符。

     伪代码:

    class Solution {
    private:
        int w;
        int h;
        
    public:
        bool exist(vector<vector<char>>& board, string word) {
            if(board.size()==0) return false;
            h = board.size();
            w = board[0].size();
            for(int i=0; i<w; i++){
                for(int j=0; j<h; j++){
                    if(search(board, word, 0, i, j))
                        return true;
                }
            }
            return false;
        }
        
        bool search(vector<vector<char>>& board, const string& word, int d, int x, int y){
            if(x<0 || x==w ||y<0 || y==h || word[d]!=board[y][x])
                return false;
            //found the last char of the word
            if(d == word.length()-1)
                return true;
            //走过之后标记为不能走
            char cur = board[y][x];
            board[y][x]=0;
            bool found = search(board, word, d+1, x+1, y) 
                || search(board, word, d+1, x, y+1)
                || search(board, word, d+1, x-1, y)
                || search(board, word, d+1, x, y-1);
            //递归结束后再标记回来
            board[y][x] = cur;
            return found;
        }
    };

     

    BFS:python实现,用队列先进先出实现。

    #字典
    graph ={
        "A":["B","C"],
        "B":["A","C","D"],
        "C":["A","B","D","E"],
        "D":["B","C","E","F"],
        "E":["C", "D"],
        "F":["D"]
    }
    def BFS(graph, s):  #s结点
        queue = []  #数组来实现队列
        queue.append(s)
        seen = set()  #集合
        seen.add(s)
        while(len(queue)):
            vertex = queue.pop(0)
            nodes = graph[vertex]
            for w in nodes:
                if w not in seen:
                    queue.append(w)
                    seen.add(w)
            print(vertex)

    DFS: 用栈的后进先出来实现。

    def DFS(graph, s):  #s结点
        stack = []  #数组来实现栈
        stack.append(s)
        seen = set()
        seen.add(s)
        while(len(stack)):
            vertex = stack.pop()
            nodes = graph[vertex]
            for w in nodes:
                if w not in seen:
                    stack.append(w)
                    seen.add(w)
            print(vertex)

    从A走到任一点的最短路径可以用这个图打印出来了。用映射表格来记录每一个结点的前一个结点。

    问:从A到E的最短路径是哪一条?

    答:从点E出发,它的前一个结点是C,再找到A,结束。

    映射可以用字典来写。

    def BFS(graph, s):  #s结点
        queue = []  
        queue.append(s)
        seen = set()
        seen.add(s)
        parent = {s: None} #字典来实现映射
        
        while(len(queue)):
            vertex = queue.pop(0)
            nodes = graph[vertex]
            for w in nodes:
                if w not in seen:
                    queue.append(w)
                    seen.add(w)
                    parent[w] = vertex
            print(vertex)
        return parent

    这道题是真心难,它用到了Trie树中的insert函数和深度优先搜索。先把words里的单词插入到Trie树中,其中Trie树里有个string变量叫str,用来存储当前是一个单词的字符串。然后使用两层for循环,在board里搜索Trie树的每个结点。

    class Solution {
    public:
        struct TrieNode{
            TrieNode* child[26];
            string str;
            TrieNode(): str(""){
                for(auto& a: child)
                    a = nullptr;
            }
            ~TrieNode(){
                delete[] child;
            }
        };
        
        struct Trie{
            TrieNode* root = new TrieNode();
            void insert(string word){
                TrieNode* p = root;
                for(char a:word){
                    int i = a -'a';
                    if(!p->child[i])
                        p->child[i] = new TrieNode();
                    p = p->child[i];
                }
                p->str = word;
            }
        };
    
        vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
            vector<string> res;
            int n = board.size();
            int m = board[0].size();
            if(n==0 || m==0 || words.empty()) return res;
            //记录是否访问过
            vector<vector<bool>> visit(board.size(), vector<bool>(board[0].size(), false));
            Trie T;
            for(auto& a:words)
                T.insert(a);
            for(int i=0; i<n; ++i){
                for(int j=0; j<m; ++j){
                    if(T.root->child[board[i][j]-'a'])
                        search(board, T.root->child[board[i][j]-'a'], i, j, visit, res);
                }
            }
            return res;
        }
        
        void search(vector<vector<char>>& board, TrieNode* p, int i, int j, vector<vector<bool>>& visit, vector<string>& res){
            if(!p->str.empty()){
                res.push_back(p->str);
                p->str.clear();
            }
            int d[][2]={{-1,0},{1,0},{0,-1},{0,1}};
            visit[i][j] = true;
            for(auto& a:d){
                int nx = a[0]+i, ny = a[1]+j;
                if(nx>=0 && nx<board.size() && ny>=0 && ny<board[0].size() && !visit[nx][ny] && p->child[board[nx][ny]-'a'])
                    search(board, p->child[board[nx][ny]-'a'], nx, ny, visit, res);
            }
            
            visit[i][j] = false;
        }
    };

     

    class Solution {
    public:
        /*
         * @param words: a set of words without duplicates
         * @return: all word squares
         */
        struct TrieNode{
            vector<TrieNode*> children;
            vector<int> index;
            TrieNode():children(26, nullptr){}
        };
        
        TrieNode* buildTrie(vector<string>& words){
            TrieNode* root = new TrieNode();
            for(int i=0; i<words.size(); ++i){
                TrieNode* t = root;
                //对于每一个单词遍历
                for(int j=0; j<words[i].size(); ++j){
                    if(!t->children[words[i][j]-'a'])
                        t->children[words[i][j]-'a'] = new TrieNode();
                    t = t->children[words[i][j]-'a'];
                    t->index.push_back(i);   //储存当前前缀的单词所在words中的索引
                }
            }
            return root;
        }
        
        vector<vector<string>> wordSquares(vector<string> &words) {
            // write your code here
            vector<vector<string>> res;
            if(words.size()==0) return res;
            TrieNode* root = buildTrie(words);
            vector<string> out(words[0].size());
            for(auto word: words){
                out[0] = word;
                dfs(words, root, 1, out, res);
            }
            return res;
        }
        
        void dfs(vector<string> &words, TrieNode* root, int level, vector<string>& out, vector<vector<string>>& res){
            string str = "";
            //vector<string> out;
           // vector<vector<string>> res;
            if(level >= words[0].size()){
                res.push_back(out);
                return;
            }
            for(int i=0; i<level; ++i)
                str += out[i][level];
            TrieNode* p = root;
            for(int i=0; i<str.size(); ++i){
                //在Trie树中找符合前缀的所有单词
                if(!p->children[str[i]-'a'])
                    return;
                p = p->children[str[i]-'a'];
                
            }
            for(int id : p->index){
                //将符合前缀条件的单词放入out中
                out[level] = words[id];
                dfs(words, root, level+1, out, res);
            }
        }
    };

    Word Squares:

    解题步骤:
    Store all words into a trie. Iterate through the words.

      • For each word:
        • create a new list. Add the word into the list.
        • Search the trie for all the words that have the correct prefix. For each of these words:
          • Add it to the list.
          • Continue searching for the next prefix recursively.
          • The recursion reaches its base case when the size of the list is equal to the length of a word. In this case, we've found a word square.
  • 相关阅读:
    SCI写作经典替换词,瞬间高大上!(转)
    最佳化常用测试函数 Optimization Test functions
    算法复杂度速查表
    VS 代码行统计
    CPLEX IDE 菜单栏语言设置( 中文 英文 韩文 等多国语言 设置)
    如何从PDF文件中提取矢量图
    Matlab无法打开M文件的错误( Undefined function or method 'uiopen' for input arguments of type 'char)
    visual studio 资源视图 空白 解决方案
    MFC DialogBar 按钮灰色不响应
    嗨翻C语言笔记(二)
  • 原文地址:https://www.cnblogs.com/Bella2017/p/11117254.html
Copyright © 2011-2022 走看看