剑值offer面试题12:矩阵中的路径

题目描述:给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

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

示例 1:输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:输入:board = [["a","b"],["c","d"]], word = "abcd"
输出:false

解题思路
DFS + 剪枝
DFS:深度搜索二叉树
剪枝:遇到不符合条件的情况,提前返回,即答案中代码的

// 如果越界(行或列) 或 匹配到的字符与 word 当前遍历到的下标不同,直接返回
if(i<0||i>=row||j<0||j>=col||board[i][j]!=word[k])  return false;

DFS 解析
递归参数: 当前元素在矩阵 board 中的行列索引 i 和 j,当前目标字符在 word 中的索引 k 。
终止条件:
        返回 false:
                         行或列索引越界
                         当前矩阵元素与目标字符不同
                          当前矩阵元素已访问过(通过将访问过的字符置空)
        返回 true: k = word.length() - 1 ,即字符串 word 已全部匹配。
递推过程:
标记当前矩阵元素: 将 board[i][j] 修改为空字符'\0',代表此元素已访问过,防止之后搜索时重复访问。
搜索下一单元格: 朝当前元素的 上、下、左、右 四个方向开启下层递归,使用或连接(代表只需找到一条可行路径就直接返回,不再做后续 DFS ),并记录结果至 res 。
还原当前矩阵元素: 将 board[i][j] 元素还原至初始值,即 word[k] 。
返回值: 返回布尔量 res ,代表是否搜索到目标字符串。

class Solution {
public:
    bool exist(vector<vector<char>>& board, string word)
    {
        len=word.size();
        row=board.size();
        col=board[0].size();
        for(int i=0;i<row;i++)//从矩阵的任意一个位置开始搜索
        {
            for(int j=0;j<col;j++)
            {
                if(dfs(board,word,i,j,0)) return true;
            }
        }
        return false;
    }
    int row,len,col;

    bool dfs(vector<vector<char>>& board, string word,int i,int j,int k)
    {
        if(i<0||i>=row||j<0||j>=col||board[i][j]!=word[k]) return false;
        if(k==len-1) return true;
        board[i][j]='\0';
        bool res=dfs(board,word,i-1,j,k+1)||dfs(board,word,i+1,j,k+1)
                ||dfs(board,word,i,j-1,k+1)||dfs(board,word,i,j+1,k+1);
        board[i][j]=word[k];//搜索完成后,不管return 什么,board必须还原,因为主函数里面还要
        //换一个位置为起点再次进行搜索。如果不还原,则board数组里面有些位置被更改,影响主函数里 
          从下一个位置开始搜索的结果,board不还原对于单次搜索来说是没有影响的,但是我们要从board 
          数组里面的任意位置为起点进行多次搜索,所以每一次搜索完成后,在回溯的过程中board数组必 
          须还原。
        return res;
    }
};

  • dfs + 回溯;
  • 使用二维布尔数组记录之前的位置是否已经被访问过,如果已经被访问过的话,则在 dfs 的过程中,直接 return false 即可。也就是说,此路已经不通了;
  • 如果当前遍历到的字符不等于 board[i][j] 位置上的字符,那么说明此路也是不通的,因此返回 false;
  • 至于递归结束的条件:如果指针 k 能够来到 word 的最后一个字符,那么说明能够在矩阵 board 中找到一条路径,此时返回 true;
  • 在遍历到当前 board[i][j] 的时候,首先应将该位置的 visited[i][j] 设置为 true,表明访问过;
  • 然后,递归地去 board[i][j] 的上下左右四个方向去找,剩下的路径;
  • 在 dfs 的过程当中,如果某条路已经不通了,那么那么需要回溯,也就是将 visited[i][j] 位置的布尔值重新赋值为 fasle;
  • 最后,返回 ans 即可。
class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) 
    {
        row = board.size();
        col = board[0].size();
        len = word.size();
        vector<vector<bool>> visited(row, vector<bool>(col, false));
        for(int i=0; i<row; i++)
        {
            for(int j=0; j<col; j++)
            {
                 // 从 (0, 0) 点开始进行 dfs 操作,不断地去找,
                // 如果以(0,0) 点没有对应的路径的话,那么就从 (0, 1) 点开始去找
                if(dfs(board, word, visited, i, j, 0)) return true;
            }
        }
     
         // 遍历结束没找到false
        return false;
    }

    int row, col, len;

    bool dfs(vector<vector<char>>& board, string& word, vector<vector<bool>>& visited, int i, int j, int k)
    {
         // 判断传入参数的可行性 i 与图行数row比较,j与图列数col比较
        // i,j初始都是0,都在图左上角
        // k是传入字符串当前索引,一开始是0,如果当前字符串索引和图当前索引对应的值不相等,表示第一个数就不相等
        // 所以继续找第一个相等的数。题目说第一个数位置不固定,即路径起点不固定(不一定是左上角为第一个数)

        // 如果board[i][j] == word[k],则表明当前找到了对应的数,就继续执行(标记找过,继续dfs 下上右左)
        if(i<0 || i>=row || j<0 || j>=col || visited[i][j] == true || board[i][j] != word[k])
        {
            return false;
        }

        // 表示找完了,每个字符都找到了
        if(k == len-1) return true;

        //标记当前网格上的点已经访问
        visited[i][j] = true;

        bool ans = false;

        // 顺序是 上 下 左 右;上面找到了对应索引的值所以寻找字符串的下一个字符k+1
        ans = dfs(board, word, visited, i-1, j, k+1) || dfs(board, word, visited, i+1, j, k+1)
            || dfs(board, word, visited, i, j-1, k+1) || dfs(board, word, visited, i, j+1, k+1);
        
        // 还原找过的元素,因为之后可能还会访问到(不同路径)  
        visited[i][j] = false;
        // 返回结果,如果false,则if(dfs(board, words, i, j, 0)) return true;不会执行,就会继续找
        return ans;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值