剑指 Offer 12. 矩阵中的路径

题目描述:

 

思路总结:

我们要设置一个visited,用于记录在当前还正确的路线中该格子是否访问过。

注意:并不是你一个格子访问过就把其设置为访问过,只有当格子访问过且已经纳入当前的正确路线的时候我们才将其visted设置为1。

下面是具体思路:

主要采用了2个技巧:visited访问表和递归的思想。visited表是和board表同样形状的二维表。

1、首先,那么我们继续按照从上到下,从左到右的顺序访问board表,直到遇到了和word单词中第一个字母相等的格子。然后设置这个格子的字母的visited=1.

2、假设我们现在已经找到了word单词的前m个字母的正确格子路线。设置当前到达的第m个格子的visited=1.

3、然后,我们再判断其相邻位置的元素(相邻位置的元素至多4个)是否等于word单词的第m+1个字母。如果4个相邻位置中的元素中一个满足条件的话,那么说明当前仍然属于正确的线路。然后转到第三步。否则,如果,4个相邻的元素都不等于的话,那么说明当前的路线错误,那么撤销步骤2 中被设置为访问过(visited=1)的格子m的visited=1,重新设置为没有访问过visited=0。

4、重复步骤2、3。直到所有board格子都访问结束(表示没有找到正确路线,return false),或者word单词中的所有字母均遍历结束(说明找到正确的路线,return true)。

更多细节见如下代码:

class Solution {
public:
    bool check(vector<vector<char>>& board, vector<vector<int>>& visited, int i, int j, string& s, int k){
        if(board[i][j]!=s[k]){
            return false;
        }else if(k == s.length()-1){ //表示字符串已经扫描完
            return true;
        }
        visited[i][j] = true;
        vector<pair<int, int>> dirctions{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        bool result = false;
        //分别看上下左右相邻的元素
        for(const auto& dir: dirctions){
            int newi = i + dir.first, newj = j + dir.second;
            if(newi>=0&&newi<board.size()&&newj>=0&&newj<board[0].size()){
                if(!visited[newi][newj]){ //如果这个相邻点没有被访问过
                    //如果没有访问过,就看从这个格子开始能不能构成后面的字符串。
                    bool flag = check(board, visited, newi, newj, s, k+1);
                    if(flag){
                        result = true;
                        break;
                    }
                }
            }
        }
        //没有纳入正确路线的恢复设置其为没有访问过。
        visited[i][j] = false;
        return result;
    }

    bool exist(vector<vector<char>>& board, string word) {
        int h = board.size(); // 求得board的行数
        int w = board[0].size(); // 求得board的列数
        // 初始化一个和board同形的二维数组
        vector<vector<int>> visited(h, vector<int>(w));
        for(int i = 0; i < h; i++){ //要将每个起点遍历完
            for(int j=0; j<w; j++){
                bool flag = check(board, visited, i, j, word, 0);
                if(flag){
                    return true;
                }
            }
        }
        return false;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值