【剑指offer】【C++】12. 矩阵中的路径

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

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

在这里插入图片描述

例如,在上面的 3×4 的矩阵中包含单词 "ABCCED"(单词中的字母已标出)。

示例 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
 

提示:

1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

考点:

深度优先搜索+剪枝

主要思路:

  1. **起始位置。**由于起始位置并不确定,因此需要通过遍历矩阵,挨个查找。而后针对每个起始点,使用深度优先搜索来查找字符串。
  2. **深度优先搜索。**对于每个起始点,使用深度优先搜索。深度优先搜索是,只要满足条件就一直往下走,先走通一条路。当遇到不满足条件的就回溯,站在上一个节点位置(有多个路口可以走,如A\B\C),转向走下一个路口B,如路口B还不满足,就走路口C。
  3. **约束条件。**在确定某个节点是否满足的条件是,如果 走过的路 或者 走到了边界 或者 字符不对应,那么就不能选择这个节点,因此返回false;如果走过的节点索引k等于word.size()-1,那么就说明找到了,返回true。
  4. **递归实现。**由于只需要找到一条路就可以,因此针对当前节点的多个选择,只要有一个路径选择正确(返回true)即可,因此多个递归调用的关系是 或|| 的关系。
  5. **时间复杂度。**时间复杂度为O(3^k MN)。每个字符需要判断3次,总共k个字符,而需要参与判断的起始点有MN个。
  6. **空间复杂度。**空间复杂度为O(k)。递归操作最多需要入栈k次。

下图以及代码来源:

面试题12. 矩阵中的路径( DFS + 剪枝 ,清晰图解)

在这里插入图片描述

代码:

class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        row = board.size()-1;
        col = board[0].size()-1;
        int k=0;
        for(int i=0; i<=row; ++i){
            for(int j=0; j<=col; ++j){//每个点作为起始点
                if(findchar(board, word, i, j, k)) return true;//如果当前点作为起始点满足条件,那么就返回true
            }
        }
        return false;   //Line 12: Char 5: error: non-void function does not return a value in all control paths 每个途径都要返回bool
    }
private:
    int row, col;
    bool findchar(vector<vector<char>>&board, string& word, int i, int j, int k){//针对每个起始点进行搜索
        if(i>row || j>col ||i<0 || j<0 || board[i][j]!=word[k]) return false;//如果越界,或者当前节点不等于word中第k个字符,则不满足条件;
 //如果当前节点等于word中第k个字符,那么再看是否所有字符查找完毕
        if(k==word.size()-1) return true;//所有字符查找完毕就返回true
        board[i][j] = '\0'; //如果没有查找完毕,并且当前字符找的正确,那么就标记为空字符,后边就不能重复这个字符了
        bool res = findchar(board, word, i-1, j, k+1) || findchar(board, word, i+1, j, k+1)||//进行上下左右查找,只要有一个满足条件就可以返回true
        findchar(board, word, i, j-1, k+1) || findchar(board, word, i, j+1, k+1);
        board[i][j] = word[k];//恢复这个字符,因为以后可能有别的起始点查找,这个过程是回溯的过程。在每层递归下都会恢复。
        return res;
    }
};

出现问题:

数组越界问题:计算row以及col,和判断越界的代码不相符导致数组越界。

/*
AddressSanitizer:DEADLYSIGNAL
=================================================================
==42==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x00000034c6d7 bp 0x7ffd9ede0200 sp 0x7ffd9ede01a0 T0)//数组越界
==42==The signal is caused by a READ memory access.
==42==Hint: this fault was caused by a dereference of a high value address (see register values below).  Dissassemble the provided pc to learn which register was used.
    #9 0x7f7ccbee70b2  (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
AddressSanitizer can not provide additional info.
==42==ABORTING

*/
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值