|
| 1 | +# 题目地址(Minimum Dropping Path Sum) |
| 2 | + |
| 3 | +https://binarysearch.com/problems/Minimum-Dropping-Path-Sum |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +``` |
| 8 | +You are given a two-dimensional list of integers matrix. Return the minimum sum you can get by taking a number in each row with the constraint that any row-adjacent numbers cannot be in the same column. |
| 9 | +
|
| 10 | +Constraints |
| 11 | +
|
| 12 | +1 ≤ n ≤ 250 where n is the number of rows in matrix |
| 13 | +2 ≤ m ≤ 250 where m is the number of columns in matrix |
| 14 | +Example 1 |
| 15 | +Input |
| 16 | +matrix = [ |
| 17 | + [4, 5, -2], |
| 18 | + [2, 6, 1], |
| 19 | + [3, 1, 2] |
| 20 | +] |
| 21 | +Output |
| 22 | +1 |
| 23 | +Explanation |
| 24 | +We can take -2 from the first row, 2 from the second row, and 1 from the last row. |
| 25 | +
|
| 26 | +Example 2 |
| 27 | +Input |
| 28 | +matrix = [ |
| 29 | + [3, 0, 3], |
| 30 | + [2, 1, 3], |
| 31 | + [-2, 3, 0] |
| 32 | +] |
| 33 | +Output |
| 34 | +1 |
| 35 | +Explanation |
| 36 | +We can take 0 from the first row, 3 from the second row, and -2 from the last row. |
| 37 | +``` |
| 38 | + |
| 39 | +## 前置知识 |
| 40 | + |
| 41 | +- [动态规划](https://github.com/azl397985856/leetcode/blob/master/thinkings/dynamic-programming.md "动态规划") |
| 42 | + |
| 43 | +## 公司 |
| 44 | + |
| 45 | +- 暂无 |
| 46 | + |
| 47 | +## 思路 |
| 48 | + |
| 49 | +这道题是不同路径(或者杨辉三角)的换皮题。 |
| 50 | + |
| 51 | +这道题是让我们每一行选择一个数,使得数字和最小。唯一的限制是相邻行拿的数字不能列相同(其实就是不能上下紧挨着拿)。 |
| 52 | + |
| 53 | +一个可能的暴力思路是: |
| 54 | + |
| 55 | +- 先取第一行。第一行有 n (n 为列数)个选择,那就挨个试。 |
| 56 | +- 接下来取第二行。第二行有 n-1 个选择,那就挨个试。 |
| 57 | +- 接下来取第三行。第三行有 n-1 个选择,那就挨个试。 |
| 58 | +- 。。。 |
| 59 | + |
| 60 | +不要小看暴力法, 这是一种解决问题的思维习惯。 |
| 61 | + |
| 62 | +如果你将上面的过程画成一棵树的话,那么可以看出时间复杂度大概是和底层的节点数是一个数量级的,是指数级别的。就算不画树,你也不难看出大概的计算次数是 n _(n -1) _ (n - 1) ...(一共 m - 1 个 n -1)。那么我们可以优化么? |
| 63 | + |
| 64 | +实际上是可以的。我们先不考虑题目的限制”相邻行拿的数字不能列相同“。那么我们的策略就变成了贪婪, 只要每一行都取最小的不就行了?时间复杂度是 $O(m * n)$。 |
| 65 | + |
| 66 | +那么加上这个限制会有什么不同么?以题目的例子为例: |
| 67 | + |
| 68 | +``` |
| 69 | +matrix = [ |
| 70 | + [3, 0, 3], |
| 71 | + [2, 1, 3], |
| 72 | + [-2, 3, 0] |
| 73 | +] |
| 74 | +``` |
| 75 | + |
| 76 | +贪心的做法第一行要选 0,第二行要选 1,不过违反了限制。那我们有必要把所有的选择第一行和第二行的组合计算出来么(就像上面的暴力法那样)?其实我们只**记录上一行的最小和次小值**即可。如果出现了上面的情况,那么我们可以考虑: |
| 77 | + |
| 78 | +- 选择 1 和上一行次小值(3 + 1) |
| 79 | +- 选择行次小值和上一行最小值(2 + 0) |
| 80 | + |
| 81 | +剩下的逻辑也是如此。 |
| 82 | + |
| 83 | +最终我们返回**选择到达**最后一行的**最小值**即可。 |
| 84 | + |
| 85 | +## 代码 |
| 86 | + |
| 87 | +代码支持:Python3 |
| 88 | + |
| 89 | +Python3 Code: |
| 90 | + |
| 91 | +```py |
| 92 | +class Solution: |
| 93 | + def solve(self, matrix): |
| 94 | + dp = [(0, -1)] |
| 95 | + m, n = len(matrix), len(matrix[0]) |
| 96 | + for i in range(m): |
| 97 | + next_dp = [(float("inf"), -1), (float("inf"), -1)]# (smallest, 2nd smallest) |
| 98 | + for j in range(n): |
| 99 | + for v, k in dp: |
| 100 | + if k == j: |
| 101 | + continue |
| 102 | + nxt = matrix[i][j] + v |
| 103 | + if nxt < next_dp[0][0]: |
| 104 | + next_dp = [(nxt, j), next_dp[0]] |
| 105 | + elif nxt < next_dp[1][0]: |
| 106 | + next_dp[1] = (nxt, j) |
| 107 | + break |
| 108 | + dp = next_dp # rolling array |
| 109 | + return dp[0][0] |
| 110 | + |
| 111 | +``` |
| 112 | + |
| 113 | +**复杂度分析** |
| 114 | + |
| 115 | +- 时间复杂度:$O(m*n)$ |
| 116 | +- 空间复杂度:$O(1)$ (使用了滚动数组优化) |
| 117 | + |
| 118 | +以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 |
0 commit comments