Skip to content

Latest commit

 

History

History
162 lines (118 loc) · 4.87 KB

0931._Minimum_Falling_Path_Sum.md

File metadata and controls

162 lines (118 loc) · 4.87 KB

931. Minimum Falling Path Sum

难度: Medium

刷题内容

原题链接

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

内容描述

Given a square array of integers A, we want the minimum sum of a falling path through A.

A falling path starts at any element in the first row, and chooses one element from each row.  The next row's choice must be in a column that is different from the previous row's column by at most one.

 

Example 1:

Input: [[1,2,3],[4,5,6],[7,8,9]]
Output: 12
Explanation: 
The possible falling paths are:
[1,4,7], [1,4,8], [1,5,7], [1,5,8], [1,5,9]
[2,4,7], [2,4,8], [2,5,7], [2,5,8], [2,5,9], [2,6,8], [2,6,9]
[3,5,7], [3,5,8], [3,5,9], [3,6,8], [3,6,9]
The falling path with the smallest sum is [1,4,7], so the answer is 12.

 

Note:

1 <= A.length == A[0].length <= 100
-100 <= A[i][j] <= 100

解题方案

思路 1 - 时间复杂度: O(row * col^2)- 空间复杂度: O(row * col)******

上来写了个递归,超时,真的蠢。。

class Solution(object):
    def minFallingPathSum(self, A):
        """
        :type A: List[List[int]]
        :rtype: int
        """
        def find(A, idx):
            if not A or len(A) == 0:
                return 0
            
            if idx == 0:
                lookup[len(A), idx] = min(A[0][0]+find(A[1:], 0), A[0][1]+find(A[1:], 1))
                return lookup[len(A), idx]
            elif idx == len(A[0])-1:
                lookup[len(A), idx] = min(A[0][-1]+find(A[1:], idx), A[0][-2]+find(A[1:], idx-1))
                return lookup[len(A), idx]
            else:
                lookup[len(A), idx] = min(A[0][idx-1]+find(A[1:],idx-1),A[0][idx]+find(A[1:],idx),A[0][idx+1]+find(A[1:],idx+1))
                return lookup[len(A), idx]
        
        res = sys.maxsize
        lookup = {}
        for idx, num in enumerate(A[0]):
            if (len(A[1:]), idx) in lookup:
                res = min(res, num+lookup[len(A[1:]), idx])
            else:
                res = min(res, num+find(A[1:], idx))
            
        return res

思路 2 - 时间复杂度: O(row * col)- 空间复杂度: O(row * col)******

先梳理下要求。 给一个数组,数组从上至下,想找到一条路径 A,这条路径落到最下面的时候的总和是最小的。 每一次下落可选的点是,左边,自身,右边。

[ [1,2,3], [4,5,6], [7,8,9] ]

若从 1 这个点开始,
那么第二次下落可选的点为 [4, 5],1 是最左边了,没有更左边一位的数了。 第三次若选 4 则可选的点为 [7, 8],同上。 若选 5 则可选的点为 [7, 8, 9] 左 中 右。

  1. 一开始可能想到的是贪心的,只能从最上面开始下落,那一开始就选最小的,然后不断选最小的不就可以了吗? 对于所有的情况,贪心往往得到的是次优解,而不是最优解。

  2. 能想到贪心,进一步可以先到动态规划(DP)。 对于每一个点来说,要想保证它是当前最小的,那么就需要在它上面的 左 中 右 三个点里找到一个最小的值给自己。

从下至上我们来看,4 可以选择的点为 [1, 2],那么它要想保证加上一个值最小,要选的只能是 1 。 5 则可以选的点为 [1, 2, 3],也是 1。 6 可以是 [2, 3],那么是 3。

这一层的子问题解决完之后变成了 [5(4+1), 6(5+1), 8(6+2)]。

在开始下一层,7 是 [5, 6] 里选择。 8 是 [5, 6, 7] 里选择。

class Solution(object):
    def minFallingPathSum(self, A):
        """
        :type A: List[List[int]]
        :rtype: int
        """
        if not A or len(A) == 0 or len(A[0]) == 0:
            return 0
        
        row = len(A)
        col = len(A[0]) if row else 0
            
        dp = [[0] * col for i in range(row)]
        dp[0] = A[0]
            
        for i in range(1, row):
            for j in range(col):
                if j == 0:
                    dp[i][j] = min(dp[i-1][0], dp[i-1][1]) + A[i][j]
                elif j == col-1:
                    dp[i][j] = min(dp[i-1][-1], dp[i-1][-2]) + A[i][j]
                else:
                    dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1]) + A[i][j]

        return min(dp[-1])

思路 3 - 时间复杂度: O(row * col)- 空间复杂度: O(1)******

可以写的更加简洁巧妙一些, 优化空间到O(1)

class Solution(object):
    def minFallingPathSum(self, A):
        """
        :type A: List[List[int]]
        :rtype: int
        """
        for i in range(1, len(A)):
            for j in range(len(A[0])):
                prev_left = A[i-1][j-1] if j-1 >= 0 else float('inf')
                prev_right = A[i-1][j+1] if j+1 < len(A[0]) else float('inf')
                A[i][j] += min(A[i-1][j], prev_left, prev_right)
        return min(A[-1])