路径

大家好,我是程序员吴师兄,欢迎来到 图解剑指 Offer 结构化专栏,在这个专栏里我将和大家一起学习如何用结构化的思维来思考、解题、写代码,希望能帮助你即使在面试的时候紧张也能做对。

今天分享的题目来源于的剑指 Offer 系列 面试题 12. 矩阵中的路径

题目汇总链接:https://www.algomooc.com/hi-offer

一、题目描述

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。

如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。

[["a","b","c","e"], ["s","f","c","s"], ["a","d","e","e"]]

但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

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

二、题目解析

我们依旧用 四步分析法 进行结构化的分析。

  • 模拟:模拟题目的运行。
  • 规律:尝试总结出题目的一般规律和特点。
  • 匹配:找到符合这些特点的数据结构与算法。
  • 边界:考虑特殊情况。

1、模拟

首先看一下矩阵的初始状态

我们需要在这个矩阵中寻找目标字符串 bfce,第一步要做的就是先匹配上目标字符串的第一个元素 b ,我们从矩阵的第一行第一列的元素开始匹配,找到了 a

目标字符串为 bfce,此时查找第一个元素为 a ,与目标字符串的第一个元素 b 不相同,需要在四个方向搜索,看看能不能找到符合要求的元素,我们按照上左下右的顺序进行遍历寻找。

  • 上:越界了
  • 左:越界了
  • 下:是 s ,与目标元素 b 不相同
  • 右:是 b,符合要求,依葫芦画瓢找第二个元素
  • 上:越界了
  • 左:是 a,与目标元素 f 不相同
  • 下:是 f,与目标元素 f 相同,符合要求,依葫芦画瓢找第三个元素
  • 上:根据题目要求不需要考虑
  • 左:是 s,与目标元素 c 不相同
  • 下:是 d,与目标元素 c 不相同
  • 右:是 c,与目标元素 c 相同,符合要求,依葫芦画瓢找第四个元素
  • 上:是 c,与目标元素 e 不相同
  • 左:根据题目要求不需要考虑
  • 下:是 e,与目标元素 e 相同,符合要求,寻找结束,匹配成功,返回 true

2、规律

  • 1、在搜索过程中,如果当前元素与目标元素不匹配,则回退到之前的节点再搜索
  • 2、在搜索过程中,如果当前元素与目标元素相匹配,则按照上左下右的方向进行再次搜索匹配剩下的元素
  • 3、在搜索过程中,搜索当前元素上左下右方向的元素时,会出现重复访问之前元素的情况,比如搜索匹配成功的第三个元素 c 的四个方向时,会重复访问一下 f

为了保证不重复访问节点,可以将这条路径上已经访问过的节点,修改为不在 word 当中的一个字符,保证以后再次访问时不会重复访问,这里我们将其修改为特殊字符 #

修改完后会出现一种情况,当前的节点元素与目标元素相匹配,但是在它的四个方向的节点中都找不到可以匹配到目标下一元素的节点。

比如此时当前元素 c 与目标元素 c 相匹配,但是目标下一元素为 x,而在当前元素的四个方向上都找不到 x ,需要把这个点回退,根据之前的操作,当前的节点被修改为了 #,所以为了能够回退成功,再回退操作时需要重新将 # 修改回原来的元素。

3、匹配

本题提供了一个矩阵,矩阵是一个二维数组,需要我们在二维数组中进行搜索,为了能够覆盖所有的情况,必然要使用两个嵌套的循环

在搜索过程中,当遇到匹配成功的元素,搜索其下一元素的操作与当前的操作一致,即可以使用递归

  • 递归参数:当前元素在矩阵 board 中的行列索引 ij ,当前目标字符在word 中的索引 k
  • 终止条件
    • 返回 false: (1) 行或列索引越界 (2) 当前矩阵元素与目标字符不同 (3) 当前矩阵元素已访问过
    • 返回 truek = len(word) - 1 ,即字符串 word 已全部匹配。
  • 递推工作
    • 标记当前矩阵元素:将 board[ i ] [ j ] 修改为特殊字符 # ,代表此元素已访问过,防止之后搜索时重复访问。
    • 搜索下一节点:朝当前元素的 上、左、下、右 四个方向开启下层递归。
    • 回退时还原当前矩阵元素:将 board[ i ] [ j ] 元素还原至初始值,即 word[k] 。
  • 返回值: 返回布尔量 res ,代表是否搜索到目标字符串。

4、边界

  • 1、行越界
  • 2、列越界
  • 3、矩阵元素已访问过

三、动画描述

四、图片描述

剑指 Offer 12. 矩阵中的路径.002

剑指 Offer 12. 矩阵中的路径.003

剑指 Offer 12. 矩阵中的路径.004

剑指 Offer 12. 矩阵中的路径.005

剑指 Offer 12. 矩阵中的路径.006

剑指 Offer 12. 矩阵中的路径.007

剑指 Offer 12. 矩阵中的路径.008

剑指 Offer 12. 矩阵中的路径.009

剑指 Offer 12. 矩阵中的路径.010

剑指 Offer 12. 矩阵中的路径.011

剑指 Offer 12. 矩阵中的路径.012

剑指 Offer 12. 矩阵中的路径.013

剑指 Offer 12. 矩阵中的路径.014

剑指 Offer 12. 矩阵中的路径.015

剑指 Offer 12. 矩阵中的路径.016

剑指 Offer 12. 矩阵中的路径.017

剑指 Offer 12. 矩阵中的路径.018

剑指 Offer 12. 矩阵中的路径.019

剑指 Offer 12. 矩阵中的路径.020

剑指 Offer 12. 矩阵中的路径.021

剑指 Offer 12. 矩阵中的路径.022

剑指 Offer 12. 矩阵中的路径.023

剑指 Offer 12. 矩阵中的路径.024

剑指 Offer 12. 矩阵中的路径.025

剑指 Offer 12. 矩阵中的路径.026

剑指 Offer 12. 矩阵中的路径.027

剑指 Offer 12. 矩阵中的路径.028

剑指 Offer 12. 矩阵中的路径.029

剑指 Offer 12. 矩阵中的路径.030

剑指 Offer 12. 矩阵中的路径.031

剑指 Offer 12. 矩阵中的路径.032

五、参考代码

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
class Solution {
    public boolean exist(char[][] board, String word) {
        // 先将字符串进行拆分,一个一个元素进行匹配
        char[] words = word.toCharArray();
        // 通过两层嵌套,覆盖所有的情况
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                // 以该元素为起始点,递归检查是否符合要求
                if(dfs(board, words, i, j, 0)) return true;
            }
        }
        return false;
    }

    boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        // 边界情况判断
        // 行越界
        // 列越界
        // 矩阵元素已访问过 
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;

        // 之前已经和目标字符串匹配成功了 length - 1 个字符,此时又匹配成功了最后一个元素,直接返回结果
        if(k == word.length - 1) return true;

        // 标记当前矩阵元素,将其修改为特殊字符 #  ,代表此元素已访问过,防止之后搜索时重复访问。
        board[i][j] = '#';

        // 搜索元素的四个方向 上 左 下 右,匹配下一个目标元素
        boolean res = dfs( board , word , i , j - 1 , k + 1 ) 
                   || dfs( board , word , i - 1 , j , k + 1 ) 
                   || dfs( board , word , i , j + 1 , k + 1 ) 
                   || dfs( board , word , i + 1 , j , k + 1 );

        // 回退时还原当前矩阵元素
        board[i][j] = word[k];

        // 返回结果
        return res;
    }
}

注意 :搜索元素的四个方向 上 左 下 右,匹配下一个目标元素时的代码不要拆分,否则会出现超出时间限制,因为这样做相当于每一个方向都进行了搜索,而事实上不需要,只需要找到一条符合要求的路径即可。

boolean up    = dfs(board, word, i, j - 1, k + 1);
boolean left  = dfs(board, word, i - 1, j , k + 1); 
boolean down  = dfs(board, word, i, j + 1, k + 1);
boolean right = dfs(board, word, i + 1, j , k + 1);
boolean res = up || left || down || right;

六、复杂度分析

时间复杂度

时间复杂为 O( 4k M N ),其中 M,N 分别为矩阵行列长度, K 为字符串 word 的长度,每个字符都有 4 个方向。

空间复杂度

空间复杂度为 O(K) 。

七、相关标签

  • 深度优先搜索
  • 递归
  • 数组
  • 回溯

八、参考阅读

1、https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/solution/mian-shi-ti-12-ju-zhen-zhong-de-lu-jing-shen-du-yo/

2、https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/

3、https://www.algomooc.com

本文分享自微信公众号 - 五分钟学算法(CXYxiaowu),作者:程序员吴师兄

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-04-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • (Java)路径问题(绝对路径、相对路径)

    ·以 “/” 开头的路径都是 绝对路径,不以当前文件的位置作为起始,而是以一个固定位置作为起始到达目标文件所经过的路径。

    qubianzhong
  • struts/Servlet,action转到jsp后,路径问题(struts2,jsp路径,action路径,action跳转,相对路径,绝对路径)

    用户1258909
  • [小知识点]绝对路径与相对路径.

    一枝花算不算浪漫
  • python3绝对路径,相对路径

    from __future__ import absolute_import的作用: 

    py3study
  • 相对路径和绝对路径

    根目录下有demo1和images/1.jpg,demo1下有index1.html文件和demo1.1文件夹。demo1.1下有index2.html和2.j...

    狼啸风云
  • 绝对路径和相对路径(转)

    1、相对路径-顾名思义,相对路径就是相对于当前文件的路径。网页中一般表示路径使用这个方法。

    山河木马
  • 伪路径

    1.什么是伪路径? 存在于设计之中,之所以叫伪路径,是因为这样的路径并未发挥真正的功能,在时序分析时不需要我们去分析。 2.为什么设置伪路径? 去除无效的时序...

    瓜大三哥
  • 最短路径(一)——多源最短路径

    引出问题:多源最短路径的问题 暑假,小文准备去一些城市旅游。为了节省经费以及方便计划旅程,小文希望知道任意两个城市之间的最短路径。假如有四个城市八条公路。 我们...

    深度学习思考者
  • 关于"绝对路径"和"相对路径"

    作为一个phper,一开始学习的时候,可能都接触过绝对路径和相对路径,但是也可能很多没学基础的人,直接撸tp去了,根本不了解路径,一遇到问题就两眼一抹黑瞎几把问...

    仙士可
  • 文件的相对路径和绝对路径以及根相对路径

      如果当前文档和目标文档所在的文件夹位置平行,则书写为:文件夹名称/目标文档全称;

    阿豪聊干货
  • Linux中的绝对路径和相对路径

    Zoctopus
  • 相对路径和绝对路径的区别

    在HTML里只要涉及文件的地方(如超级链接、图片等)就会涉及绝对路径与相对路径的概念。  1.绝对路径     绝对路径是指文件在硬盘上真正存在的路径。例如“b...

    猿人谷
  • HTML中的相对路径与绝对路径

    HTML初学者会经常遇到这样一个问题,如何正确引用一个文件。比如,怎样在一个HTML网页中引用另外一个HTML网页作为超链接(hyperlink)?怎样在一个网...

    猿人谷
  • tomcat设置访问路径与实际路径

    Happy、Liu
  • 相对路径和绝对路径的区别

    绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)例如: C:\xyz\test.txt 代表了test.txt文件的绝对路...

    狼啸风云
  • javaWeb项目中的路径格式 请求url地址 客户端路径 服务端路径 url-pattern 路径 获取资源路径 地址 url

    javaweb项目中有很多场景的路径 客户端的POST/GET请求,服务器的请求转发,资源获取需要设置路径等 这些路径表达的含义都有不同,所以想要更好的书写规范...

    noteless
  • Classpath路径? 原

    1、src不是classpath, WEB-INF/classes,lib才是classpath,WEB-INF/ 是资源目录, 客户端不能直接访问。

    wuweixiang
  • 路径复制

    使用路径复制复制很简单。在Windows资源管理器中,右键单击任何文件,文件夹或文件组,然后显示上下文菜单。在其中,您将看到两个新项目。

    云深无际
  • 不同路径

    一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下...

    用户7962184

扫码关注云+社区

领取腾讯云代金券