力扣HOT100之回溯:79. 单词搜索

这道题花了我好长的时间,本来测试用例都过了,结果后面的输入样例超时了,无语。然后去看了下灵神的题解,感觉我的思路和他未优化过的版本思路是一样的,但是他的不会超时,我的会超时。先说说思路,这道题还是定义一个dfs()函数,输入参数有linecolumni,分别代表当前访问的元素所在的行数、列数,和当前正在处理第i位数字。若当前位置已经被访问过或者当前位置上的字符与word[i]不相等,则直接返回false,若当前位置的字符未被访问过,并与word[i]相等,且长度也已经达标了,匹配成功,返回true。如果上述情况都不满足,则说明还需要进一步探索。我们首先将(line, column)处标记为已访问,然后依次向四个方向遍历,并递归调用dfs()函数,如果下一地点的位置未超出索引且递归调用返回的结果为true,则说明已经找到一条符合要求的路径,直接返回true,如果遍历了四个方向都没有找到路径则说明这条路行不通,返回false。在主函数中,我们遍历每一个位置,并以之为起点,调用dfs(),一旦出现返回true的情况就立马返回true,循环如果顺利结束则说明整个地图都找不出合法的路径,返回false。下面是我的超时代码。

cpp 复制代码
class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        bool result = false;
        string path;
        int m = board.size();   //m行
        int n = board[0].size();  //n列
        vector<vector<bool>> is_visit(m, vector<bool>(n, false));
        vector<vector<int>> dirs = {
            {0, 1},   //右
            {0, -1},  //左
            {1, 0},   //下
            {-1, 0}   //上
        };
        //处理第i位上的字符,当前探索到(line, column)的位置
        auto bfs = [&](this auto&& bfs, int line, int column, int i){
            //递归终止条件
            if(i == word.size()){
                if(path == word)
                    result = true;
                return ;
            }
            //判断是否超出边界
            if(line < 0 || line >= m || column < 0 || column >= n)
                return ;    //超出边界,直接返回
            //递归主体逻辑
            if(!is_visit[line][column] && board[line][column] == word[i]){
                //当前位置的字符匹配上了,且未使用过
                path += board[line][column];
                is_visit[line][column] = true;
                //向四周探索
                for(auto dir : dirs){
                    int next_line = line + dir[0];
                    int next_column = column + dir[1];
                    bfs(next_line, next_column, i + 1);
                }
                //回溯
                path.pop_back();
                is_visit[line][column] = false;
            }
        };
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                bfs(i, j, 0);
                if(result) return result;
            }  
        }
        return result;
    }
};

上述代码超时的原因是合法的路径可能有多个,我们只需要找到一条就行,因此在向四周探索的时候,按照代码的逻辑,尽管已经找到了一条合法的路径,但是代码还是会继续向其他方向搜索,这就会导致超时,因此我们需要在找到路径时及时终止搜索。此外,在遍历四个方向时,一定要用引用的方式,否则赋值拷贝的过程也会增加耗时,最终导致超时。以下是经过小优化后的代码(不是最优,还可以进一步剪枝,详见灵神题解

cpp 复制代码
class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        int m = board.size();   //m行
        int n = board[0].size();  //n列
        vector<vector<bool>> is_visit(m, vector<bool>(n, false));  //用于标记是否访问过
        vector<vector<int>> dirs = {
            {0, 1},   //右
            {0, -1},  //左
            {1, 0},   //下
            {-1, 0}   //上
        };
        //处理第i位上的字符,当前探索到(line, column)的位置
        auto dfs = [&](this auto&& dfs, int line, int column, int i) -> bool{
            /**********递归终止条件**********/
            //1.当前位置已经被访问过或当前位置上的字符与word[i]不相等,匹配失败
            if(is_visit[line][column] || board[line][column] != word[i])   
                return false;
            //2.当前位置的字符未被访问过,并与word[i]相等,且长度也已经达标了,匹配成功
            if(i + 1 == word.size())   
                return true;
            /**********递归主体逻辑**********/
            //当前位置的字符匹配上了,且未使用过
            is_visit[line][column] = true;   //标记为已访问
            //向四周探索
            for(auto& dir : dirs){  //这里必须用引用,要不然会超时
                int next_line = line + dir[0];
                int next_column = column + dir[1];
                if((next_line >= 0 && next_line < m) 
                && (next_column >= 0 && next_column < n)
                &&  dfs(next_line, next_column, i + 1))
                    return true;
            }
            //回溯
            is_visit[line][column] = false;
            return false;
        };
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(dfs(i, j, 0))   //搜到了
                    return true;
            }  
        }
        return false;
    }
};
相关推荐
weisian15120 分钟前
力扣经典算法篇-13-接雨水(较难,动态规划,加法转减法优化,双指针法)
算法·leetcode·动态规划
天才测试猿38 分钟前
自动化测试工具:Selenium详解
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
敲代码的瓦龙1 小时前
C++?继承!!!
c语言·开发语言·c++·windows·后端·算法
简简单单做算法1 小时前
基于FPGA的二叉决策树cart算法verilog实现,训练环节采用MATLAB仿真
算法·决策树·fpga开发·cart算法·二叉决策树
白熊1881 小时前
【机器学习基础】机器学习入门核心算法:K-近邻算法(K-Nearest Neighbors, KNN)
算法·机器学习·近邻算法
北京地铁1号线1 小时前
MMdetection推理验证输出详解(单张图片demo)
前端·算法
oioihoii1 小时前
C++23 新成员函数与字符串类型的改动
算法·c++23
似水এ᭄往昔2 小时前
【数据结构】——二叉树堆(下)
数据结构·算法
GG不是gg2 小时前
Prim算法剖析与py/cpp/java语言实现
算法
秋山落叶万岭花开ღ2 小时前
探索数据结构之顺序表:从入门到精通
数据结构·python·算法