在问 · 算法题解

931. 下降路径最小和

中等动态规划滚动数组动态规划力扣原题 ↗

题目描述

输入一个 n x n 的整数矩阵 matrix。

下降路径从第一行的任意一格出发,每次走到下一行,直到最后一行,每行恰好选一格。若当前在 (row, col),下一步只能到 (row + 1, col - 1)、(row + 1, col) 或 (row + 1, col + 1) 中位于矩阵内的格子。

路径和是路径上所有格子的值之和。返回所有下降路径中路径和的最小值。

示例 1
输入:matrix = [[2,1,3],[6,5,4],[7,8,9]]
输出:13

解释:例如 1 -> 5 -> 7 或 1 -> 4 -> 8,和都是 13。

示例 2
输入:matrix = [[-19,57],[-40,-5]]
输出:-59

解释:走 -19 -> -40,和为 -59。

数据范围

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 100
  • -100 <= matrix[i][j] <= 100

解题思路:滚动数组动态规划

设 dp[j] 为到达当前行第 j 列的最小路径和。下一行的格子 (i,j) 只能从上一行的 j-1、j、j+1 三列过来,所以 nxt[j] = min(dp[j-1], dp[j], dp[j+1]) + matrix[i][j](越界的列不参与)。逐行推到最后,答案是最后一行 dp 的最小值。

为什么正确

处理完第 i 行后,dp[j] 等于从第 0 行任意位置到 (i,j) 的所有合法路径中的最小和。

复杂度分析

时间 O(n²),空间 O(n)。

易错点

不能在 dp 上原地从左到右更新:算 nxt[j+1] 时要用上一行的 dp[j],原地覆盖后就是当前行的值了。用新数组 nxt,或一次性保存旧值。第一列和最后一列只有两个来源。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def minFallingPathSum(self, matrix: List[List[int]]) -> int:
        n = len(matrix)
        dp = matrix[0][:]
        for i in range(1, n):
            nxt = [0] * n
            for j in range(n):
                best = dp[j]
                if j > 0:
                    best = min(best, dp[j - 1])
                if j < n - 1:
                    best = min(best, dp[j + 1])
                nxt[j] = best + matrix[i][j]
            dp = nxt
        return min(dp)

载入编辑器,自己跑一遍 →

其他解法

记忆化搜索是自顶向下、主解法是自底向上,两者时间都是 O(n²);滚动数组把空间压到 O(n)。

解法 2:记忆化搜索 时间 O(n²),空间 O(n²)

定义 dfs(i, j) 为从 (i, j) 出发向下走到最后一行的最小路径和。最后一行直接返回 matrix[i][j]。否则取下一行 j - 1、j、j + 1 三个位置中的最小值再加上 matrix[i][j],结果存入备忘录。答案是第一行所有 dfs(0, j) 的最小值。

自顶向下的写法和状态定义一一对应,容易从递归思路推出。需要 O(n²) 备忘录和 O(n) 递归栈,空间比滚动数组大。

from functools import lru_cache

class Solution:
    def minFallingPathSum(self, matrix: List[List[int]]) -> int:
        n = len(matrix)

        @lru_cache(maxsize=None)
        def dfs(i, j):
            if i == n - 1:
                return matrix[i][j]
            best = dfs(i + 1, j)
            if j > 0:
                best = min(best, dfs(i + 1, j - 1))
            if j < n - 1:
                best = min(best, dfs(i + 1, j + 1))
            return matrix[i][j] + best

        return min(dfs(0, j) for j in range(n))

动态规划 专题的其他题目

查看 动态规划 全部题目 →