152. 乘积最大子数组

题目描述

152. 乘积最大子数组

解题方法

暴力搜索

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        dp = [[nums[i] for i in range(len(nums))] for j in range(len(nums))]
        max_product = dp[0][0]
        for i in range(len(nums)):
            dp[i][i] = nums[i]
            max_product_i = dp[i][i]
            for j in range(i+1,len(nums)):
                dp[i][j] = dp[i][j-1] * nums[j]
                max_product_i = max(max_product_i,dp[i][j])
            max_product = max(max_product_i,max_product)
        return max_product

时间复杂度 O ( n 2 ) O(n^2) O(n2)

动态规划

对于子数组问题按照最大子序和中的思路,定义dp[i] 为以i为结尾的子串的某种状态。

  1. 尝试1:
    按照最大子序和那样定义状态dp[i]为以i为结尾的子串的最大乘积。
    状态转移为: dp[i] = max(dp[i-1]*nums[i], nums[i])。
    运行后发现这种状态转移不正确,如果当前的nums[i]为负数,以当前nums[i]为结尾的最大子串乘积此时有可能为该负数乘以该元素之前最小的负乘积,不一定是nums[i]乘以之前元素的最大乘积。
  2. 尝试2:
    1. 状态定义:同时定义了以i为结尾的子串的最大乘积dp_max[i]和以i为结尾的子串最小乘积dp_min[i].
    2. 状态转移:
      • dp_max[i] = max(nums[i] * dp_max[i-1], nums[i] * dp_min[i-1], nums[i])
      • dp_min[i] = min(nums[i] * dp_max[i-1], nums[i] * dp_min[i-1], nums[i])
      • max_product = max(max_product, dp_max[i])
class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        dp_min = [nums[i] for i in range(len(nums))]
        dp_max = [nums[i] for i in range(len(nums))]
        
        max_product = nums[0]
        for i in range(1, len(nums)):
            max_i = nums[i] * dp_max[i-1]
            min_i = nums[i] * dp_min[i-1]
            dp_max[i] = max(max_i,min_i,nums[i])
            dp_min[i] = min(max_i,min_i,nums[i])
            max_product = max(max_product,dp_max[i])
        return max_product

反思总结

  1. 对于子串问题可定义状态dp[i]为以nums[i]结尾的子串的某种状态
  2. 该问题比最大子序和问题加升了难度。最大自序和问题只要每一状态的子序和为最大对于后面的状态就是最优的选择,可以认为是单调的。而最大乘积问题,每一状态的子序和最大时,后续状态不一定在之前的最大乘积状态下取得最大,例如有可能后面出现一负数,乘以前面子串的最小负乘积,负负得正这种情况下取得最大。所以每个状态下也存储最小的乘积。
  3. 对于max(dp[i-1]+nums[i], nums[i])的理解:
    1. 当前的状态不一定是上一状态的最优解+当前元素就是最优的,对于上一状态的结果为负数情况,加上当前元素后更小了,此时只有当前元素时结果最优。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值