《LeetCode 329 矩阵中的最长递增路径 记忆化搜索DFS解法》

一.题目

329. 矩阵中的最长递增路径 - 力扣(LeetCode)

二.思路讲解

2.1 思路讲解

本题要求矩阵中最长递增路径的长度。我们可以采用暴力枚举起点 + 深度优先搜索的思路:从矩阵的每个格子出发,向上下左右四个方向探索,只允许走向值更大的格子,并统计该路径的长度。

但直接递归会导致大量重复计算,因此引入记忆化搜索 :用一个备忘录数组 memo 记录每个格子已经计算出的最长递增路径长度,在递归前先查表,若已计算则直接返回,否则递归计算后存入备忘录。这样每个格子只计算一次。通过这种"暴力枚举 + 记忆化"的优化,就能高效求出整个矩阵的最长递增路径长度。

三.代码演示

cpp 复制代码
class Solution {
public:
    int row,col;
    int bx[4] = {0,0,1,-1};
    int by[4] = {1,-1,0,0};
    int memo[201][201];
    int longestIncreasingPath(vector<vector<int>>& matrix) 
    {
        row = matrix.size(),col = matrix[0].size();
        int ret = 0;
        for(int i = 0;i < row;i++)
        {
            for(int j = 0;j < col;j++)
            {
                ret = max(ret,dfs(matrix,i,j));
            }
        }
        return ret;
    }
    int dfs(vector<vector<int>>& matrix,int i,int j)
    {
        if(memo[i][j] != 0) return memo[i][j];
        int path = 1;//包括自己
        for(int k = 0;k < 4;k++)
        {
            int x = i + bx[k],y = j + by[k];
            if(x >= 0 && y >= 0 && x < row && y < col && matrix[x][y] > matrix[i][j])
            {
                
                path = max(path,dfs(matrix,x,y) + 1);
                
            }
        }
        memo[i][j] = path;
        return path;
    }
};

四.代码讲解

一、全局变量与数据结构
  • rowcol:成员变量,存储矩阵的行数和列数。

  • 方向数组 bx[4]by[4]:表示上下左右四个方向的偏移量,用于探索相邻格子。

  • memo[201][201] :二维数组,作为备忘录,memo[i][j] 表示从格子 (i, j) 出发的最长递增路径长度,初始为 0(表示未计算)。

二、主函数 longestIncreasingPath
  1. 获取矩阵尺寸 rowcol

  2. 初始化结果变量 ret = 0

  3. 遍历所有格子,对每个格子 (i, j) 调用 dfs(matrix, i, j) 计算以该格子为起点的最长递增路径长度,并更新 ret 为最大值。

  4. 返回 ret

三、递归函数 dfs

dfs(matrix, i, j) 返回从格子 (i, j) 出发的最长递增路径长度。执行流程如下:

1. 查备忘录

如果 memo[i][j] != 0,说明该子问题已经计算过,直接返回存储的值。这是记忆化搜索的核心优化,避免重复计算。

2. 初始化当前路径长度

path 初始化为 1,因为至少包含当前格子本身。

3. 向四个方向探索

遍历四个方向,计算新坐标 (x, y)

  • 边界检查x >= 0 && y >= 0 && x < row && y < col

  • 递增条件matrix[x][y] > matrix[i][j] 若满足,则递归调用 dfs(matrix, x, y) 得到以 (x, y) 为起点的最长递增路径长度,加上当前格子后长度即为 dfs(matrix, x, y) + 1。用 max 更新 path

4. 存入备忘录并返回

将计算得到的 path 存入 memo[i][j],然后返回 path

四、关键细节
  • 记忆化:每个格子只计算一次。

  • 递归方向:由于只能走向值更大的格子,不存在循环依赖,递归能正确终止。

  • 备忘录初始值 :用 0 表示未计算,因为路径长度至少为 1,不会与有效值冲突。

五、流程图