Leetcode 212. Word Search II

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;
    }
};

猜你喜欢

转载自blog.csdn.net/hu694028833/article/details/78691518
今日推荐