Skip to content

1289 Minimum Falling Path Sum II

Approach 1: bottom-up

This is a constrained problem when you can't fall directly down to the same column. Therefore, the optimal path would be falling the last row's minimum value except for the same column. Brute force it will be O(N^3) time complexity.

Complexity

  • Time complexity: \(O(N^3)\)
  • Space complexity: \(O(N)\)
class Solution:
    def minFallingPathSum(self, grid: List[List[int]]) -> int:
        n = len(grid)
        # initialize
        prev = grid[0]

        def helper(i,arr):
            """get min of array except for index i
            """
            res = float('inf')
            for j,item in enumerate(arr):
                if j == i:
                    continue
                res = min(res,item)
            return res

        for i in range(1,n):
            curr = [0 for _ in range(n)]
            for j in range(n):
                curr[j] = grid[i][j] + helper(j,prev)

            prev = curr.copy()
        return min(prev)                

Approach 2 Optimized

我们发现,对于每一行,我们只需要找到最小的两个元素,然后更新下一行的值。这样我们可以将时间复杂度降低到\(O(N^2)\)

Complexity

  • Time complexity: \(O(N^2)\)
  • Space complexity: \(O(n)\)

Code Implementation

class Solution:
    def minFallingPathSum(self, grid: List[List[int]]) -> int:
        n = len(grid)
        if n == 1:
            return grid[0][0]

        # initialize
        prev = grid[0]
        curr = [0 for _ in range(n)]

        def helper(arr):
            """get two smallest element of an arr and its index
            it returns like [(smallest,idx),(second_smallest,idx)]
            """
            smallest,smallest_i = float('inf'),None
            sec_smallest,sec_i = float('inf'),None

            for i,val in enumerate(arr):
                if val < smallest:
                    sec_smallest,sec_i = smallest,smallest_i
                    smallest,smallest_i = val,i
                elif val < sec_smallest:
                    sec_smallest,sec_i = val,i
            return [(smallest,smallest_i),(sec_smallest,sec_i)]

        for i in range(1,n):            
            lookup = helper(prev)
            for j in range(n):
                if j != lookup[0][1]:
                    curr[j] = lookup[0][0] + grid[i][j]
                else:
                    curr[j] = lookup[1][0] + grid[i][j]
            prev = curr.copy()
        return min(curr)                

这里还可以进行优化,其实我们都不care具体的index,只需要知道最小的两个值即可。因此我们可以上一行最小的两个值即可。

Complexity

  • Time complexity: \(O(N^2)\)
  • Space complexity: \(O(1)\)
class Solution:
    def minFallingPathSum(self, grid: List[List[int]]) -> int:
        n = len(grid)
        if n == 1:
            return grid[0][0]


        def get_two_smallest(arr):
            """get two smallest element of an arr and its index
            it returns like [(smallest,idx),(second_smallest,idx)]
            """
            smallest,smallest_i = float('inf'),None
            sec_smallest,sec_i = float('inf'),None

            for i,val in enumerate(arr):
                if val < smallest:
                    sec_smallest,sec_i = smallest,smallest_i
                    smallest,smallest_i = val,i
                elif val < sec_smallest:
                    sec_smallest,sec_i = val,i
            return [(smallest,smallest_i),(sec_smallest,sec_i)]
        # initialize
        prev = get_two_smallest(grid[0])

        for i in range(1,n):            
            smallest,smallest_i = float('inf'),None
            sec_smallest,sec_i = float('inf'),None
            for j in range(n):
                if j != prev[0][1]:
                    candidate = prev[0][0] + grid[i][j]
                else:
                    candidate = prev[1][0] + grid[i][j]

                if candidate < smallest:
                    sec_smallest,sec_i = smallest,smallest_i
                    smallest,smallest_i = candidate,j
                elif candidate < sec_smallest:
                    sec_smallest,sec_i = candidate,j

            prev = [(smallest,smallest_i),(sec_smallest,sec_i)]
        return prev[0][0]