牛客题解 | 矩阵最长递增路径

题目

题目链接

题目主要信息:
  • 矩阵内是非负数,求最长的递增路径的长度
  • 移动方向可以是上下左右,不能超出边界,这将是递归的判定条件
  • 同一条路径不能有重复的单元格,需要有记忆
举一反三:

学习完本题的思路你可以解决如下题目:

BM57. 岛屿数量

方法一:深度优先搜索(推荐使用)

知识点:深度优先搜索(dfs)

深度优先搜索一般用于树或者图的遍历,其他有分支的(如二维矩阵)也适用。它的原理是从初始点开始,一直沿着同一个分支遍历,直到该分支结束,然后回溯到上一级继续沿着一个分支走到底,如此往复,直到所有的节点都有被访问到。

思路:

既然是查找最长的递增路径长度,那我们首先要找到这个路径的起点,起点不好直接找到,就从上到下从左到右遍历矩阵的每个元素。然后以每个元素都可以作为起点查找它能到达的最长递增路径。

如何查找以某个点为起点的最长递增路径呢?我们可以考虑深度优先搜索,因为我们查找递增路径的时候,每次选中路径一个点,然后找到与该点相邻的递增位置,相当于进入这个相邻的点,继续查找递增路径,这就是递归的子问题。因此递归过程如下:

  • 终止条件: 进入路径最后一个点后,四个方向要么是矩阵边界,要么没有递增的位置,路径不能再增长,返回上一级。
  • 返回值: 每次返回的就是本级之后的子问题中查找到的路径长度加上本级的长度。
  • 本级任务: 每次进入一级子问题,先初始化后续路径长度为0,然后遍历四个方向(可以用数组表示,下标对数组元素的加减表示去往四个方向),进入符合不是边界且在递增的邻近位置作为子问题,查找子问题中的递增路径长度。因为有四个方向,所以最多有四种递增路径情况,因此要维护当级子问题的最大值。

具体做法:

  • step 1:使用一个dp数组记录 i i i j j j处的单元格拥有的最长递增路径,这样在递归过程中如果访问到就不需要重复访问。
  • step 2:遍历矩阵每个位置,都可以作为起点,并维护一个最大的路径长度的值。
  • step 3:对于每个起点,使用dfs查找最长的递增路径:只要下一个位置比当前的位置数字大,就可以深入,同时累加路径长度。

图示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Java实现代码:

import java.util.*;
public class Solution {
   
   
    //记录四个方向
    private int[][] dirs = new int[][] {
   
   {
   
   -1, 0}, {
   
   1, 0}, {
   
   0, -1}, {
   
   0, 1}};
    private int n, m;
    //深度优先搜索,返回最大单元格数
    public int dfs(int[][] matrix, int[][] dp, int i, int j) {
   
   
        if(dp[i][j] != 0)
            return dp[i][j];
        dp[i][j]++;
        for (int k = 0; k < 4; k++) {
   
   
            int nexti = i + dirs[k][0];
            int nextj = j + dirs[k][1];
            //判断条件
            if(nexti >= 0 && nexti < n && nextj >= 0 && nextj < m && matrix[nexti][nextj] > matrix[i][j])
                dp[i][j] = Math.max(dp[i][j], dfs(matrix, dp, nexti, nextj) + 1);
        }
        return dp[i][j];
    }
    public int solve (int[][] matrix) {
   
   
        //矩阵不为空
        if (matrix.length == 0 || matrix[0].length == 0) 
            return 0;
        int res = 0;
        n = matrix.length;
        m = matrix[0].length;
        //i,j处的单元格拥有的最长递增路径
        int[][] dp = new int[m + 1][n + 1];  
        for(int i = 0; i < n; i++) 
            for(int j = 0; j < m; j++)
                //更新最大值
                res = Math.max(res, dfs(matrix, dp, i, j)); 
        return res;
    }
}

C++实现代码:

class Solution {
   
   
public:
    //记录四个方向
    int dirs[4][2] = {
   
   {
   
   -1, 0}, {
   
   1, 0}, {
   
   0, -1}, {
   
   0, 1}};
    int n, m;
    //深度优先搜索,返回最大单元格数
    int dfs(vector<vector<int> > &matrix, vector<vector<int> > &dp, int i, int j) {
   
   
        if(dp[i][j] != 0)
     
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值