Leetcode 120:三角形最小路径和(最详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/82797218

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

例如,给定三角形:

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

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

说明:

如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

解题思路

一个最简单的思路就是将所有数往下加,但是在层数>=3的时候会出现这样的问题。

2      	 	  
5 6     	  
11 (10,11) 13	  

那么我们这个时候就取最小值10,然后再往下加。

class Solution:
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        if not triangle:
            return 0
        return self._minimumTotal(0, 0, triangle)

    def _minimumTotal(self, row, col, triangle):
        if row + 1 == len(triangle):
            return triangle[row][col]

        return triangle[row][col] + min(self._minimumTotal(row + 1, col, triangle), self._minimumTotal(row + 1, col + 1, triangle))

但是这样做存在着大量的重复运算(在哪呢?)。我们可以通过记忆化搜索的方式来优化上面的问题。

class Solution:
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        if not triangle:
            return 0
        
        mem = [[None for i in range(len(triangle))] for j in range(len(triangle))]
        print(mem)
        return self._minimumTotal(0, 0, triangle, mem)

    def _minimumTotal(self, row, col, triangle, mem):
        if row + 1 == len(triangle):
            return triangle[row][col]

        if mem[row][col]:
            return mem[row][col]

        mem[row][col] = triangle[row][col] + \
                                min(self._minimumTotal(row + 1, col, triangle, mem), \
                                self._minimumTotal(row + 1, col + 1, triangle, mem))

        return mem[row][col]

显然这种写法很麻烦,我们追求的是优雅的编程( ̄▽ ̄)"。我们不妨将金字塔倒过来

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

我们只要再相邻的元素中选出最下的值,然后往对应的下一层加即可。例如[4,1,8,3]41比,1小,所以我们将1加到下一层的6。接着,考虑18,我们将1加到下一层的5,接着考虑83,我们将3加到7,以此类推下去。

基于这个思想我们可以写出这样的代码

class Solution:
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        if not triangle:
            return 0
        
        for row in range(len(triangle) - 1, 0, -1):
            for col, _ in enumerate(triangle[row - 1]):
                triangle[row - 1][col] += min(triangle[row][col] ,triangle[row][col + 1])
        
        return triangle[0][0]

当然这里的for col, _ in enumerate(triangle[row - 1]):写成for col in range(row):更加简洁。当然我们可以将上面的代码继续简化

import functools
class Solution:
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        return functools.reduce(lambda a,b:[f+min(d,e)for d,e,f in zip(a,a[1:],b)],triangle[::-1])[0]

Just one line!!!但是这种写法一点也不优雅。

reference:

https://leetcode.com/problems/triangle/discuss/38827/One-liner-in-Python

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/82797218