单词搜索II--前缀树的应用

0x01.问题

此题建立在上个问题的基础上:单词搜索–DFS

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
你可以假设所有输入都由小写字母 a-z 组成。

C++函数形式:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words)

注:此题来源于Leetcode,详情前往:戳我前往

0x02.简要分析

这个问题是 单词搜索 的升级版,不同在于,这次要求的是找多个字符串。

再使用上次的方法,当然可以解决问题,不过比较暴力,而且时间上可能会超时。

那么我们可以想办法优化一下。

用贪心的思维来想,就是怎样才能减少真正计算的次数呢?

我们发现对于单词ATFWUS来说,如果ATFWUSMAX已经存在,那么作为这个单词的前缀,肯定也是存在的,这样我们就可以减少很多不必要的遍历。

所以我们可以使用 前缀树

于是我们首先想到的就是,遍历一个单词时,可以先去前缀树中查找一下,看是不是已经搜索完毕的前缀,如果是,那么就不必要去搜索。

这是一个很好的思路,但是,实际上,时间的效率不会提高很多,而且空间的消耗还增大了。
因为你仍然需要对每个单词去搜索,如果运气不好,不但没有减少时间,反而因为要记录这些值而加大了空间的消耗。

我们可以换一个角度思考,如果我们事先把每个单词都存入前缀树中,这样,我们只需要从每个结点开始去搜索,在搜索的过程是可以做到所有单词一起搜索了的,这样就可以避免很多不必要的搜索。于是我们的思路是:

  • 将所有的单词存入前缀树。
  • 每个顶点都去搜索一次(原因是单词的开头可能在任意位置)
  • 如果遇到前缀树中不存在的相应情况,就返回,停止搜索。
  • 如果遇到了单词的尾部,也就是isEnd的值为真时,那么就认为找到了这个单词。并且把isEnd置为假,目的是防止同一个单词重复检测。
  • 整体的搜索思路是DFS。

我们在结构上需要做的改变是:

  • 需要在前缀树的基础上增加一个str字段,目的就是方便查询到尾部的时候,直接获取该单词。
  • 搜索函数,可以改为遍历每个顶点,从每个顶点开始去搜索一次。

0x03.解决代码–前缀树

class Trie {
private:
    bool isEnd;
    Trie*next[26];
    string str;
public:
    Trie() {
        isEnd=false;
        memset(next, 0, sizeof(next));
    }
     
    void insert(string word) {
        Trie*node=this;
        for(char c:word){
            if(node->next[c-'a']==NULL){
                node->next[c-'a']=new Trie();               
            }
            node=node->next[c-'a'];
        }
        node->isEnd=true;
        node->str=word;
    }
    
    void search(vector<string>& result,vector<vector<char>>& board) {
        Trie*node=this;
        for(int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                helper(result,board,i,j,node);
            }
        }
    }   

    void helper(vector<string>& result,vector<vector<char>>& board,int x,int y,Trie*node){
        if(node->isEnd==true){
            node->isEnd=false;//避免d同样的单词重复寻找
            result.push_back(node->str);
            return;
        }
        if(x<0||x==board.size()||y<0||y==board[x].size()) return;
        if(board[x][y]=='0'||node->next[board[x][y]-'a']==nullptr) return; 
        node=node->next[board[x][y]-'a'];
        char temp=board[x][y];
        board[x][y]='0';
        helper(result,board,x+1,y,node);
        helper(result,board,x-1,y,node);
        helper(result,board,x,y+1,node);
        helper(result,board,x,y-1,node);
        board[x][y]=temp;
    }
};

class Solution {
public:
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        Trie *root=new Trie();
        vector<string>result;
        for(auto word:words){
            root->insert(word);
        }
        root->search(result,board);
        return result;
    }
};
    

ATFWUS --Writing By 2020–03–22

发布了159 篇原创文章 · 获赞 179 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ATFWUS/article/details/105033747