Leetcode 212. Word Search II

本文介绍了一种针对WordSearch II问题的有效解决方法,通过优化DFS搜索策略来提高搜索效率,减少冗余搜索,并实现对输入字符串的有效匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

212. Word Search II

题目说明

Given a 2D board and a list of words from the dictionary, find all words in the board.

Each word must be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

For example,
Given words = ["oath","pea","eat","rain"] and board =

[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]

Return ["eat","oath"].

题目解释
本题的输入是一个字符矩阵和字符串数组。在矩阵中定义上下左右位置为相邻,可连成路径,对于每一个输入的字符串,需要检测能否在字符矩阵中查找对应的路径,该路径连成的字符串等于输入字符串。将能够查找到的字符串返回。

思路

本题是一个很经典的dfs,需要在字符矩阵中进行dfs搜索。但本题使用传统的dfs搜索会超时。因此需要改进,减少搜索复杂度。

选择搜索出发点

我们需要确定dfs的搜索起点,遍历字符矩阵具有较大的复杂度,进行预处理,对每一个字符出现的位置进行统计,得到一个位置的vector。这样在选择搜索起点时,就直接选择vector中的位置,对应代码如下:

unordered_map<char, vector<pair<int, int> > >ump;
for (int i = 0; i < height; ++i)
   for (int j = 0; j < width; ++j)
       ump[board[i][j]].push_back(make_pair(i, j));

减少搜索复杂度

分析
使用传统的dfs搜索,我们需要对每一个字符串,进行完整的dfs搜索,这里具有较大的冗余,比如有两个字符串abcabcd,我们在搜索abc的时候,假如没有搜索到,那我们在搜索abcd的时候,我们已经不需要搜索就可以判断搜索不到了,因此这样就进行了无用的搜索。因此我们需要记录可以搜索到的字符串和不可搜索到的字符串,减小不必要的搜索。另外需要注意搜索字符串可能有重复,需要去重。

具体做法
对于每一个字符串,我们依次选择前1,2,3...i个字符串进行搜索,如果搜索到某个字符串,我们记录下该子串可以搜到,某一个字符串搜不到,就记录下改子串搜不到。每次搜索的时,先查找是否有这个字符串的记录,如果有就不需要进行搜索了。具体的代码如下:

unordered_map<string, int> usi;     // 记录不能通过的样例
unordered_map<string, int> ysi;     // 记录能通过的样例
unordered_map<char, vector<pair<int, int> > >ump;
for (auto s : words)
{       
      char c = s[0];
      vector<pair<int, int> > vp = ump[c];
      // 将字符串从短到长依次搜索
      for (int i = 1; i <= s.size(); i++)
      {
          string str = s.substr(0, i);
          if (usi[str])       // 如果已经有一个片段无法搜索到,则不需要再延伸搜索
              break;   
          if (ysi[str])       // 如果这个片段可以搜索到,如果已经是全部,需要记录下来,因为可能有更长的段搜不到,但部分是可以搜到的
          {
              if(i==s.size())
                  vs.push_back(str);
              continue;
          }
          bool f = false;
          // 从所有位置开始进行搜索
          for (auto p : vp)
          {
              vector<vector<bool> >vvb(height, vector<bool>(width, false));
              vvb[p.first][p.second] = true;
              if (solve(str, p.first, p.second, 1, vvb, board))
              {
                  if (i==s.size())
                      vs.push_back(str);
                  f = true;
                  break;
              }
          }
          // 记录能否搜索到
          if (!f)
              usi[str] ++;
          else
              ysi[str] ++;
      }
  }

完整代码

class Solution {
public:
    int dire[4][2] = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
    int height, width;

    // dfs搜索
    bool solve(string s, int x, int y, int idx, vector<vector<bool> > &vvb, vector<vector<char>>& board)
    {
        if (idx == s.size())
            return true;
        bool f = false;
        for (int i = 0; i < 4; i++)
        {
            int x0 = x + dire[i][0];
            int y0 = y + dire[i][1];
            if (x0 >= 0 && x0 < height && y0 >= 0 && y0 < width)
            {
                if (s[idx] == board[x0][y0] && vvb[x0][y0]==false)
                {
                    vvb[x0][y0] = true;
                    if (solve(s, x0, y0, idx + 1, vvb, board))
                        return true;
                    vvb[x0][y0] = false;
                }
            }
        }
        return false;
    }

    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        unordered_map<string, int> usi;     // 记录不能通过的样例
        unordered_map<string, int> ysi;     // 记录能通过的样例
        vector<string> vs;
        height = board.size();
        if (height == 0)
            return vs;
        width = board[0].size();
        // 先进行去重
        unordered_map<string, int> ui;
        for (auto s : words)
            ui[s]++;
        words.clear();
        for (auto it = ui.begin(); it != ui.end(); ++it)
            words.push_back(it->first);
        // 存取每个字母的位置,用于选择出发点
        unordered_map<char, vector<pair<int, int> > >ump;
        for (int i = 0; i < height; ++i)
            for (int j = 0; j < width; ++j)
                ump[board[i][j]].push_back(make_pair(i, j));
        for (auto s : words)
        {       
            char c = s[0];
            vector<pair<int, int> > vp = ump[c];
            // 将字符串从短到长依次搜索
            for (int i = 1; i <= s.size(); i++)
            {
                string str = s.substr(0, i);
                if (usi[str])       // 如果已经有一个片段无法搜索到,则不需要再延伸搜索
                    break;   
                if (ysi[str])       // 如果这个片段可以搜索到,如果已经是全部,需要记录下来,因为可能有更长的段搜不到,但部分是可以搜到的
                {
                    if(i==s.size())
                        vs.push_back(str);
                    continue;
                }
                bool f = false;
                // 从所有位置开始进行搜索
                for (auto p : vp)
                {
                    vector<vector<bool> >vvb(height, vector<bool>(width, false));
                    vvb[p.first][p.second] = true;
                    if (solve(str, p.first, p.second, 1, vvb, board))
                    {
                        if (i==s.size())
                            vs.push_back(str);
                        f = true;
                        break;
                    }
                }
                // 记录能否搜索到
                if (!f)
                    usi[str] ++;
                else
                    ysi[str] ++;
            }
        }
        return vs;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值