[LeetCode][C++]单词搜索 II

单词搜索 II

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例:
输入:
words = [“oath”,“pea”,“eat”,“rain”] and board =
[
\quad [‘o’,‘a’,‘a’,‘n’],
\quad [‘e’,‘t’,‘a’,‘e’],
\quad [‘i’,‘h’,‘k’,‘r’],
\quad [‘i’,‘f’,‘l’,‘v’]
]

输出: [“eat”,“oath”]

说明:
你可以假设所有输入都由小写字母 a-z 组成。

提示:
你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。


思路:
对于此类的单词搜索,我们首先想到的就是前缀树,提示1中的更大数据量的测试也提示了我们使用前缀树。
对于此类需要一个字母一个字母按顺序匹配的,我们采用深度优先遍历,此时需要考虑DFS的边界条件。

代码:

class Solution {
public:
    
    //Trie节点定义
    struct TrieNode {
       bool isStr;  //根结点至该节点是否为完整的字符串
       string word;  //若为完整的字符串,则其对应的字符串      
       TrieNode *next[26];  //下一个节点
    };
    
    vector<string> res;   //存放结果
    TrieNode *root=new TrieNode();  //前缀树根节点
    
    //构建前缀树
    void insert(string word)
    {
        TrieNode *cur=root;
        for(auto & s:word)
        {
            if(cur->next[s-'a']==NULL)
            {
                cur->next[s-'a']=new TrieNode();
            }
            cur=cur->next[s-'a'];
        }
        cur->isStr=true;
        cur->word=word;
    }
    
    //定义深度优先搜索
    void DFS(vector<vector<char>>& board, int i, int j,  TrieNode* root)
    {
        TrieNode*cur;
        char tmp=board[i][j];
        
        //递归边界
        if(tmp=='1' || root->next[tmp-'a']==NULL)
            return ;   //已访问或者节点为空,则退出
        
        //当前位置元素判断
        cur=root->next[tmp-'a'];
        if(cur->isStr) //若该节点时,恰好为一个字符串,则保存至结果
        {
            res.push_back(cur->word);
            cur->isStr=false;  //避免重复保存该字符串
        }
        
        //邻域检测
        //这个已访问的标记需要写在第38行return的后面,否则可能导致下一次检测时,board中元素没有恢复
        board[i][j]='1';
        int tmp_i,tmp_j;
        tmp_i=i-1;
        if(tmp_i>=0)
            DFS(board,tmp_i,j,cur);
        
        tmp_i=i+1;
        if(tmp_i<board.size())
            DFS(board,tmp_i,j,cur);
        
        tmp_j=j-1;
        if(tmp_j>=0)
            DFS(board,i,tmp_j,cur);
        
        tmp_j=j+1;
        if(tmp_j< board[0].size())
            DFS(board,i,tmp_j,cur);
        //恢复board中的元素,不要忘记 
        board[i][j]=tmp;
    }
    
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
         
        int row=board.size();
        if(row==0)
            return res;
        int col=board[0].size();
        if(col==0)
            return res;
        //建立前缀树
        for(auto &word:words)
            insert(word);
        //搜索
        for(int i=0;i<row;i++)
        {
            for(int j=0;j<col;j++)
            {
               DFS(board,i,j,root);
            }
        }
        return res;
    }
};

简化一下DFS:

class Solution {
public:    
    struct Trie
    {
        bool isWord=false;
        string word="";
        Trie* next[26]={nullptr};

    };

    Trie* root=new Trie();
    int m,n;
    vector<vector<int>> mark;
    vector<string> res;

    void addWord(string word)
    {
        Trie* cur=root;
        for(auto c:word)
        {
            if(cur->next[c-'a']==nullptr)
                cur->next[c-'a']=new Trie();
            cur=cur->next[c-'a'];
        }
        cur->isWord=true;
        cur->word=word;
    }


    void dfs(vector<vector<char>>& board, int i, int j, Trie* node)
    {
        if(i<0 || i>=m || j<0 || j>=n || mark[i][j] )
            return ;

        
        int ind=board[i][j]-'a';
        if(node->next[ind]==nullptr)
            return ;
        if( node->next[ind]->isWord )
        {
            res.emplace_back(node->next[ind]->word);
            node->next[ind]->isWord=false;
        }
            

        mark[i][j]=1;
        dfs(board,i-1,j,node->next[ind]);
        dfs(board,i+1,j,node->next[ind]);
        dfs(board,i,j-1,node->next[ind]);
        dfs(board,i,j+1,node->next[ind]);
        mark[i][j]=0;
    }


    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        
        for(auto s:words)
            addWord(s);
        m=board.size();
        if(m==0)  return res;
        n=board[0].size();
        if(n==0) return res;
        mark.resize(m,vector<int>(n));

        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                dfs(board,i,j,root);

        return res;        
    }
};

结果:
单词搜索 II

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值