LeetCode2024年3月16日每日一题(2684. 矩阵中移动的最大次数 )

题目

在这里插入图片描述
在这里插入图片描述

思路

这段代码实现了一个在二维网格上进行深度优先搜索(DFS)的算法,用来寻找从网格的左侧到任何位置所能达到的最大移动步数。移动规则是从当前位置只能向右上、正右或右下方向移动,并且移动的目标位置上的值必须大于当前位置上的值。算法的主要特点和步骤如下:

  1. 初始化:使用一个全局变量ans来记录遍历过程中找到的最大步数,初始值设为Integer.MIN_VALUE。使用一个二维数组dp来存储每个位置上能够达到的最大移动步数,以避免重复计算。

  2. maxMoves方法:这是主方法,接收一个二维数组grid作为输入,代表网格。它首先初始化dp数组,然后对网格的每一行的第一列进行遍历,从每个这样的位置出发调用DFS方法。

  3. DFS方法:这个方法是深度优先搜索的核心,它尝试探索所有可能的移动路径,并更新全局最大值ans。每次递归调用DFS时,都会检查当前位置是否已经计算过(即dp[i][j]不为0),如果是,则直接返回存储的值。它尝试向右上、正右、右下移动,只有在新位置的值大于当前位置的值时才会进行移动。

  4. 边界检查isOut方法用于检查给定的位置是否越界(即是否在网格之外)。

  5. 动态规划(DP)是解决这个问题的关键技术之一。在这个特定的场景中,动态规划用于存储从网格中每个位置出发,符合移动规则的最长路径长度。这种方法可以避免重复计算已经解决过的子问题,极大地提高了算法的效率。下面是关于动态规划部分的详细解释:

动态规划数组的初始化

  • dp = new int[grid.length][grid[0].length];:动态规划的数组dp与输入的网格grid具有相同的维度。数组中的每个元素dp[i][j]初始值都为0,表示从位置(i, j)出发的最长路径长度尚未计算。

使用动态规划存储中间结果

  • DFS方法中,每次递归调用都会尝试计算从当前位置出发的最长路径长度。在达到一个新的位置(i, j)时,首先检查dp[i][j]是否不为0,即这个位置的最长路径是否已经计算过。如果已经计算过(dp[i][j]不为0),则直接返回该值,这样就避免了对相同位置的重复计算。
  • 如果dp[i][j]为0,说明这个位置的最长路径还未被计算。此时,算法会通过递归探索所有可能的移动方向,计算出从该位置出发的最长路径,并将计算结果存储在dp[i][j]中。

更新动态规划数组

  • 在探索完一个位置的所有可能移动后,选择最长路径长度,将其加1(当前位置也算作一步),然后更新dp[i][j]。这个加1操作是因为,不管接下来的路径有多长,从当前位置出发至少包含了一步移动。
  • 这样,dp[i][j]就存储了从位置(i, j)出发,按照给定移动规则能够达到的最长路径长度。这个值随后可被直接使用,避免了在后续搜索过程中对同一位置的重复计算。
  1. 更新全局最大值:在DFS过程中,每次递归都会尝试更新全局最大值ans,这保证了在搜索结束时,ans存储的是所有可能路径中的最大步数。

接下来,我将在代码中添加相应的注释,以便更好地理解每个部分的功能。

代码

class Solution {
    public int ans = Integer.MIN_VALUE; // 存储最长路径的长度,初始化为Integer的最小值
    public int[][] dp; // 用于动态规划的存储,记录每个位置的最长递增路径长度

    // maxMoves函数初始化动态规划数组并开始遍历网格
    public int maxMoves(int[][] grid) {
        dp = new int[grid.length][grid[0].length]; // 初始化dp数组
        for (int i = 0; i < grid.length; i++) { // 遍历每一行
            DFS(grid, i, 0, 0); // 从每行的第一列开始深度优先搜索
        }
        
        return ans; // 返回找到的最长递增路径的长度
    }

    // DFS函数递归地搜索最长递增路径
    public int DFS(int[][] grid, int i, int j, int len) {
        ans = Math.max(ans, len); // 更新找到的最长路径长度
        int cur = 0; // 当前位置的最长递增路径长度
        if (dp[i][j] != 0) return dp[i][j]; // 如果当前位置已经计算过,直接返回结果
        
        // 检查并递归地访问当前位置右上方的位置
        if (!isOut(i - 1, j + 1, grid) && grid[i - 1][j + 1] > grid[i][j]) {
            cur = Math.max(DFS(grid, i - 1, j + 1, len + 1), cur);
        }
        // 检查并递归地访问当前位置正右方的位置
        if (!isOut(i, j + 1, grid) && grid[i][j + 1] > grid[i][j]) {
            cur = Math.max(DFS(grid, i, j + 1, len + 1), cur);
        }
        // 检查并递归地访问当前位置右下方的位置
        if (!isOut(i + 1, j + 1, grid) && grid[i + 1][j + 1] > grid[i][j]) {
            cur = Math.max(DFS(grid, i + 1, j + 1, len + 1), cur);
        }
        
        dp[i][j] = cur + 1; // 更新当前位置的最长递增路径长度
        if (cur == 0) {
            return 0; // 如果当前位置没有递增路径,则返回0
        }
        return dp[i][j]; // 返回当前位置的最长递增路径长度
    }

    // isOut函数检查给定位置是否在网格外
    public boolean isOut(int i, int j, int[][] grid) {
        return i < 0 || i >= grid.length || j < 0 || j >= grid[0].length; // 检查索引是否越界
    }

}

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值