矩阵中的路径

剑指offer的一道经典题目,

描述

请设计一个函数,用来判断在一个n乘m的矩阵中是否存在一条包含某长度为len的字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 

[abce

sfcs

adee]

矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

数据范围:0≤n,m≤20,1≤len≤25

思路:

我们并没有办法确定起点在哪里,所以我们将矩阵中的每个点都遍历一遍。

找到起点后像上下左右找到合适的下一个点,往后就可以视为递归的子问题了。

  • 终止条件: 到了矩阵的边界或者是下一个字符与这个位置的字符不匹配,或者字符串匹配完成,都需要返回,
  • 返回值: 将每条查询路径是否有这样的字符串返回,即true or false。
  • 本级任务: 检查这个位置的字符与字符串中这个字符是否匹配,并向与它相邻的四个方向(且不是来的方向)延伸子问题。

1

2

3

4

dfs(matrix, n, m, i - 1, j, word, k + 1, flag)

||dfs(matrix, n, m, i + 1, j, word, k + 1, flag)

||dfs(matrix, n, m, i, j - 1, word, k + 1, flag)

||dfs(matrix, n, m, i , j + 1, word, k + 1, flag)

访问过的节点要将flag值改为true,避免点的重复访问。如果该线路不符合,需要回溯修改flag值。

1

2

3

4

flag[i][j] = true;

...//递归

//没找到经过此格的,此格未被占用

flag[i][j] = false;

具体做法:

  • 第一步:优先处理矩阵为空的特殊情况。
  • 第二步:设置flag数组记录某一次路径中矩阵中的位置是否被经过,因此一条路径不能回头。
  • 第三步:遍历矩阵,对每个位置进行递归。
  • 第四步:递归查找的时候,到了矩阵的边界或者是下一个字符与这个位置的字符不匹配,或者节点已经访问过了,或者字符串匹配完成都结束递归。
  • 第五步:访问节点,修改flag数组,向其他四个方向延伸,回溯的时候修改flag数组。
import java.util.*;
public class Solution {
    private boolean dfs(char[][] matrix, int n, int m, int i, int j, String word, int k, boolean[][] flag){
        if(i < 0 || i >= n || j < 0 || j >= m || (matrix[i][j] != word.charAt(k)) || (flag[i][j] == true))
            //下标越界、字符不匹配、已经遍历过不能重复
            return false;
        //k为记录当前第几个字符
        if(k == word.length() - 1) 
            return true;
        flag[i][j] = true;
        //该结点任意方向可行就可
        if(dfs(matrix, n, m, i - 1, j, word, k + 1, flag)
          ||dfs(matrix, n, m, i + 1, j, word, k + 1, flag)
          ||dfs(matrix, n, m, i, j - 1, word, k + 1, flag)
          ||dfs(matrix, n, m, i , j + 1, word, k + 1, flag))
            return true; 
        //没找到经过此格的,此格未被占用
        flag[i][j] = false; 
        return false;
    }
    
    public boolean hasPath (char[][] matrix, String word) {
        //优先处理特殊情况
        if(matrix.length == 0)
            return false;
        int n = matrix.length;
        int m = matrix[0].length;
        //初始化flag矩阵记录是否走过
        boolean[][] flag = new boolean[n][m];
        //遍历矩阵找起点
        for(int i = 0; i < n; i++){  
            for(int j = 0; j < m; j++){
                //通过dfs找到路径
                if(dfs(matrix, n, m, i, j, word, 0, flag))
                    return true;
            }
        }
        return false;
    }
}

复杂度分析:

  • 时间复杂度:O(mn∗3^k),其中m与n为矩阵的边长,k为字符串的长度,遍历一次矩阵,每次条递归最坏遍历深度为k,看起来是四个方向,但是有一个方向是来的方向不重复访问,所以是三叉树型递归。
  • 空间复杂度:O(mn),辅助二维数组记录是否走过某节点使用了空间。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值