leetcode
leetcode 2651 ~ 2700
矩阵中的最长递增路径

矩阵中的最长递增路径

难度:

标签:

题目描述

Given an m x n integers matrix, return the length of the longest increasing path in matrix.

From each cell, you can either move in four directions: left, right, up, or down. You may not move diagonally or move outside the boundary (i.e., wrap-around is not allowed).

 

Example 1:

Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].

Example 2:

Input: matrix = [[3,4,5],[3,2,6],[2,2,1]]
Output: 4
Explanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.

Example 3:

Input: matrix = [[1]]
Output: 1

 

Constraints:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 200
  • 0 <= matrix[i][j] <= 231 - 1

代码结果

运行时间: 109 ms, 内存: 17.2 MB


/*
 * 思路:
 * 1. 使用深度优先搜索(DFS)加记忆化搜索(Memoization)来解决问题。
 * 2. 对于每个单元格,尝试往上、下、左、右四个方向移动。
 * 3. 使用一个二维数组memo来存储已经计算过的最长路径长度,避免重复计算。
 * 4. 使用Java Stream API进行部分操作以提升代码的可读性。
 */

import java.util.stream.IntStream;

public class Solution {
    private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    private int m, n;

    public int longestIncreasingPath(int[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0;
        m = matrix.length;
        n = matrix[0].length;
        int[][] memo = new int[m][n];
        return IntStream.range(0, m)
                        .flatMap(i -> IntStream.range(0, n).map(j -> dfs(matrix, i, j, memo)))
                        .max().orElse(0);
    }

    private int dfs(int[][] matrix, int i, int j, int[][] memo) {
        if (memo[i][j] != 0) return memo[i][j];
        int max = 1;
        for (int[] direction : directions) {
            int x = i + direction[0];
            int y = j + direction[1];
            if (x >= 0 && x < m && y >= 0 && y < n && matrix[x][y] > matrix[i][j]) {
                max = Math.max(max, 1 + dfs(matrix, x, y, memo));
            }
        }
        memo[i][j] = max;
        return max;
    }
}

解释

方法:

这个题解采用深度优先搜索(DFS)的方式,对矩阵中的每个元素进行搜索。对于每个元素,分别向上、下、左、右四个方向搜索比当前元素值小的相邻元素,找出以当前元素为起点的最长递增路径。在搜索过程中,使用记忆化的方式存储已计算过的元素的最长递增路径长度,避免重复计算。最后,取所有元素的最长递增路径长度的最大值作为整个矩阵的最长递增路径长度。

时间复杂度:

O(m*n)

空间复杂度:

O(m*n)

代码细节讲解

🦆
题解中提到使用深度优先搜索(DFS),但为什么选择DFS而不是广度优先搜索(BFS)或其他算法来解决这个问题?
在解决矩阵中的最长递增路径问题时,DFS是一个理想的选择,因为它能够深入探索可能的递增序列,直到这一路径达到终点。DFS允许我们从一个节点开始,深入探索其所有可能的递增路径,直到无法继续为止,然后回溯到前一个节点,探索另一条可能的路径。这种深度探索非常适合此类问题,因为我们需要找到最长的递增路径。相比之下,BFS从每个节点开始广泛搜索所有邻居,这在寻找最短路径问题中更常用,但对于寻找单个最长路径的问题,它不如DFS有效率,因为它需要更多的资源来同时跟踪所有在同一层的路径。此外,DFS与记忆化结合使用时,可以显著减少重复计算,使算法更加高效。
🦆
在题解的DFS实现中,递归函数search_self如何确保不会对已经访问过的路径重复计算?具体是通过哪些机制实现的?
题解中实现了记忆化来防止对同一路径的重复计算。记忆化是通过使用一个二维数组 'stores' 实现的,该数组与输入矩阵同维度。每个元素 'stores[i][j]' 存储从矩阵位置 (i, j) 开始的最长递增路径长度。在DFS过程中,每次访问一个元素时,首先检查 'stores' 数组中相应位置是否已经有值。如果已经计算过(即 'stores[i][j]' 不为空),则直接使用该值,而无需重新计算。这样,每个元素的最长递增路径长度只被计算一次,大大减少了不必要的计算量,提高了效率。
🦆
题解中提到了记忆化数组stores,这个数组的作用是什么?如何通过这个数组减少计算量?
记忆化数组 'stores' 的作用是存储每个矩阵元素为起点的最长递增路径的长度。这样,在DFS过程中,当我们尝试计算一个元素的最长递增路径时,首先会检查 'stores' 数组。如果该位置已经有值,直接使用这个值而不再进行进一步的DFS搜索,这就避免了重复计算相同的路径长度。通过这种方式,'stores' 数组减少了计算量,因为它确保每个元素的路径长度只计算一次,无论这个元素在DFS过程中被访问多少次。这种方法不仅提高了效率,还能减少递归调用的栈空间使用,从而减少内存消耗。

相关问题