10.3.1 (python) 动态规划数组类LeetCode题目 —— Minimum Path Sum & Triangle & Maximum Product Subarray

这一节的几篇,都是解析动态规划数组类题目,相对于后面的字符串类问题来说,还是比较容易的。

首先来看比较几个简单的DP题目,巩固一下前面所学套路。

64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

题目解析:

貌似63题的通过率还低些,不过就不解析了,DP框架不变,由于障碍物的关系略微修改边界和状态转移方程。

路径和还是经常和大家碰面的问题,比如在二叉树的时候。

这道题仍然不变算法框架,f(i,j)代表到达i,j点时的最小路径和,然后我们研究f(i,j)和f(i-1,j),f(i,j-1)之间的关系。对于边界的定义也略微不同。直接看代码,此次已优化了空间,这样写起来索引也好懂。。

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        dp = [0] * n
        # 第一行边界
        dp[0] = grid[0][0]
        for i in range(1, n):
            dp[i] = dp[i-1] + grid[0][i]
        for i in range(1, m):
            for j in range(n):
                if j == 0: # 第一列边界
                    dp[j] += grid[i][j]
                else:
                    # 关系式
                    dp[j] = min(dp[j], dp[j-1]) + grid[i][j]
        return dp[n-1]

 120. Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

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

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

题目解析:

还是路径问题,算法框架和状态转移方程其实都和上面的差不多啦,不同的是数组每行的数目不同,需额外注意索引和边界问题。另外对于dp数组的更新比较麻烦,索性用了两个dp数组。

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        n = len(triangle)
        if n == 1:
            return triangle[0][0]
        if n ==2:
            return triangle[0][0] + min(triangle[1][0], triangle[1][1])
        
        dp_ = [0] * n
        dp_[0] = triangle[0][0] + triangle[1][0]
        dp_[1] = triangle[0][0] + triangle[1][1]
        for i in range(3, n+1): # i是行数 索引为i-1
            dp = [0] * n
            for j in range(i):  # 每行 j代表列索引
                if j == 0:
                    dp[j] = dp_[j] + triangle[i-1][0]
                elif j == i-1:
                    dp[j] = dp_[j-1] + triangle[i-1][j]
                else:
                    dp[j] = min(dp_[j], dp_[j-1]) + triangle[i-1][j]
            dp_ = dp
        return min(dp_)

152. Maximum Product Subarray

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

题目解析:

前面有一道Maximum Subarray 最大连续和,图森破了就不介绍了。这道题是乘积,没有小数,但是会有0和负数。

1. 出现0的情况下重新往后算,另外0也可能是最大值;

2. 重点考虑负数*负数得到较大的乘积的形式,因此我们要记录两个值,一个是连续乘积最大值(正数),一个是连续乘积最小值(负数);当前数字为是正数或负数,需要用不同的方式更新这两个记录。

下面我们看代码,我们用dp_pos[i]和dp_neg[i]分别表示这两个值在i处的情况,当然我们可以优化为O(1)空间的。由于题目思路稍微复杂点,我们先写成O(n)空间的,理解了思路后再优化。

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        if not nums:
            return 0
        l = len(nums)        
        if l == 1:
            return nums[0]
        
        dp_pos = [0] * l
        dp_neg = [0] * l
        dp_pos[0] = max(nums[0], 0)
        dp_neg[0] = min(nums[0], 0)
        for i in range(1, l):
            num = nums[i]
            if num == 0:
                continue
            elif num > 0:
                # 当前数字为正
                dp_pos[i] = max(num, dp_pos[i-1] * num)
                dp_neg[i] = min(num, dp_neg[i-1] * num)
            else:
                # 当前数字为负
                dp_pos[i] = max(num, dp_neg[i-1] * num)
                dp_neg[i] = min(num, dp_pos[i-1] * num)
                
        return max(dp_pos)

这是几道稍加变形的DP题目,属于DP中必会的。后面我们会逐渐介绍有难度的题目

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值