题目地址(931. 下降路径最小和)

https://leetcode-cn.com/problems/minimum-falling-path-sum/

题目描述

  1. 给你一个 n x n 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 最小和
  2. 下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1)
  3. 示例 1
  4. 输入:matrix = [[2,1,3],[6,5,4],[7,8,9]]
  5. 输出:13
  6. 解释:下面是两条和最小的下降路径,用加粗+斜体标注:
  7. [[2,1,3], [[2,1,3],
  8. [6,5,4], [6,5,4],
  9. [7,8,9]] [7,8,9]]
  10. 示例 2
  11. 输入:matrix = [[-19,57],[-40,-5]]
  12. 输出:-59
  13. 解释:下面是一条和最小的下降路径,用加粗+斜体标注:
  14. [[-19,57],
  15. [-40,-5]]
  16. 示例 3
  17. 输入:matrix = [[-48]]
  18. 输出:-48
  19. 提示:
  20. n == matrix.length
  21. n == matrix[i].length
  22. 1 <= n <= 100
  23. -100 <= matrix[i][j] <= 100

前置知识


公司

  • 暂无

思路

这个 dp 函数的含义如下:
从第一行(matrix[0][..])向下落,落到位置 matrix[i][j] 的最小路径和为 dp(matrix, i, j)

对于 matrix[i][j],只有可能从 matrix[i-1][j], matrix[i-1][j-1], matrix[i-1][j+1] 这三个位置转移过来。
那么,只要知道到达 (i-1, j), (i-1, j-1), (i-1, j+1) 这三个位置的最小路径和,加上 matrix[i][j] 的值,就能够计算出来到达位置 (i, j) 的最小路径和
image.png

base case 为什么是 i == 0,返回值为什么是 matrix[0][j],这是根据 dp 函数的定义所决定的
回顾我们的 dp 函数定义:
从第一行(matrix[0][..])向下落,落到位置 matrix[i][j] 的最小路径和为 dp(matrix, i, j)。
根据这个定义,我们就是从 matrix[0][j] 开始下落。那如果我们想落到的目的地就是 i == 0,所需的路径和当然就是 matrix[0][j] 呗。

再说说备忘录 memo 的初始值为什么是 13212,这是由题目给出的数据范围决定的
备忘录 memo 数组的作用是什么?
就是防止重复计算,将 dp(matrix, i, j) 的计算结果存进 memo[i][j],遇到重复计算可以直接返回。
那么,我们必须要知道 memo[i][j] 到底存储计算结果没有,对吧?如果存结果了,就直接返回;没存,就去递归计算。
所以,memo 的初始值一定得是特殊值,和合法的答案有所区分。
我们回过头看看题目给出的数据范围:

matrix 是 n x n 的二维数组,其中 1 <= n <= 100;对于二维数组中的元素,有 -100 <= matrix[i][j] <= 100。

假设 matrix 的大小是 100 x 100,所有元素都是 100,那么从第一行往下落,得到的路径和就是 100 x 100 = 10000,也就是最大的合法答案。
类似的,依然假设 matrix 的大小是 100 x 100,所有元素是 -100,那么从第一行往下落,就得到了最小的合法答案 -100 x 100 = -10000。
也就是说,这个问题的合法结果会落在区间 [-10000, 10000] 中。
所以,我们 memo 的初始值就要避开区间 [-10000, 10000],换句话说,memo 的初始值只要在区间 (-inf, -10001] U [10001, +inf) 中就可以。

关键点


代码

  • 语言支持:Java

Java Code:

  1. class Solution {
  2. public int minFallingPathSum(int[][] matrix) {
  3. //返回值 取最大值
  4. int res = Integer.MAX_VALUE;
  5. //矩阵的行数 因为是正方形 所以一样
  6. int n = matrix.length;
  7. //new一个二维的dp数组
  8. memo = new int[n][n];
  9. //初始化dp
  10. for (int i = 0; i <n ; i++) {
  11. Arrays.fill(memo[i],66666);
  12. }
  13. //n-1行 i是列 matrix[n-1][0]..matrix[n-1][1]..matrix[n-1][n-1]
  14. for (int i = 0; i < n; i++) {
  15. //返回值从n-1这一行的几个数的dp方法的返回值中取一个最小的
  16. res = Math.min(res, dp(matrix, n - 1, i));
  17. }
  18. return res;
  19. }
  20. //备忘录
  21. int[][] memo ;
  22. public int dp(int[][] matrix, int i, int j) {
  23. //验证角标越界
  24. if (i >= matrix.length || j >= matrix[0].length || i < 0 || j < 0) {
  25. //实例范围是0-100 矩阵最大值为10000
  26. return 99999;
  27. }
  28. //base case
  29. if (i == 0) {
  30. return matrix[0][j];
  31. }
  32. //验证备忘录 防止重复计算
  33. if (memo[i][j] != 66666) {
  34. return memo[i][j];
  35. }
  36. //状态转移
  37. memo[i][j] = matrix[i][j] + min(
  38. dp(matrix, i - 1, j),
  39. dp(matrix, i - 1, j - 1),
  40. dp(matrix, i - 1, j + 1)
  41. );
  42. return memo[i][j];
  43. }
  44. public int min (int a , int b ,int c){
  45. return Math.min(a, Math.min(b, c));
  46. }
  47. }

复杂度分析

令 n 为数组长度。

  • 时间复杂度:931. 下降路径最小和 - 图2#card=math&code=O%28n%29&id=TJ7IK)
  • 空间复杂度:931. 下降路径最小和 - 图3#card=math&code=O%28n%29&id=EkVdr)