【Leetcode152】乘积最大子数组(动态规划)

文章目录

一、题目

二、思路

(0)读懂题意:题目的"连续"是指位置的连续,而不是说数字的连续,这是个大坑。

(1)确定状态:定义两个状态来记录当前子数组的最大乘积、最小乘积。因为在处理负数时,最小乘积乘以负数可能变为最大乘积。dp_max[i]表示以nums[i]结尾的子数组的最大乘积、dp_min[i]表示以nums[i]结尾的子数组的最小乘积。

(2)状态转移方程:对于每个元素nums[i],我们的dp_max[i]dp_min[i]可以从这三个数中确定:

  • 只包含当前元素 nums[i]
  • 当前元素与之前的最大乘积子数组乘积,即 dp_max[i-1] * nums[i]
  • 当前元素与之前的最小乘积子数组乘积,即 dp_min[i-1] * nums[i]

即状态转移方程可表示为:

python 复制代码
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])

(3)初始状态+边界条件:以第一个元素结尾的子数组最大乘积就是它本身、以第一个元素结尾的子数组最小乘积就是它本身、初始乘积最大结果为第一个元素。

(4)遍历顺序:从左到右遍历数组。

三、代码

(方法一)按照思路的代码如下,时间复杂度为O(n),空间复杂度为O(n)。

python 复制代码
class Solution(object):
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        # 初始化数组
        n = len(nums)
        dp_max = [0] * n 
        dp_min = [0] * n
        # 初始状态
        dp_max[0] = nums[0]
        dp_min[0] = nums[0]
        cheng_ans = nums[0]
        # 从第二个元素开始遍历
        for i in range(1, n):
            num = nums[i]
            dp_max[i] = max(num, dp_max[i-1]*num, dp_min[i-1]*num)
            dp_min[i] = min(num, dp_max[i-1]*num, dp_min[i-1]*num)
            cheng_ans = max(cheng_ans, dp_max[i])
        return cheng_ans

(方法二)为了优化空间复杂度,发现每次当前只利用前一次状态,所以dp_maxdp_min没必要单独用两个数组记录所有的状态。但注意在计算状态转移方程时,分别计算dp_max和dp_min都会用到上一次的dp_max和dp_min,这为了用错dp_mxn,可以直接对num确保是正数后,交换dp_max和dp_min的位置,减少max和min函数的入参个数。

python 复制代码
class Solution(object):
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        # 初始化数组
        n = len(nums)
        # 初始状态
        dp_max = nums[0]
        dp_min = nums[0]
        cheng_ans = nums[0]
        # 从第二个元素开始遍历
        for i in range(1, n):
            num = nums[i]
            if num < 0:
                dp_max, dp_min = dp_min, dp_max
            dp_max = max(num, dp_max*num)
            dp_min = min(num, dp_min*num)
            cheng_ans = max(cheng_ans, dp_max)
        return cheng_ans
相关推荐
许愿与你永世安宁10 分钟前
力扣343 整数拆分
数据结构·算法·leetcode
爱coding的橙子13 分钟前
每日算法刷题Day42 7.5:leetcode前缀和3道题,用时2h
算法·leetcode·职场和发展
满分观察网友z44 分钟前
从一次手滑,我洞悉了用户输入的所有可能性(3330. 找到初始输入字符串 I)
算法
YuTaoShao1 小时前
【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
java·算法·leetcode·矩阵
Heartoxx1 小时前
c语言-指针(数组)练习2
c语言·数据结构·算法
大熊背1 小时前
图像处理专业书籍以及网络资源总结
人工智能·算法·microsoft
满分观察网友z1 小时前
别怕树!一层一层剥开它的心:用BFS/DFS优雅计算层平均值(637. 二叉树的层平均值)
算法
杰克尼2 小时前
1. 两数之和 (leetcode)
数据结构·算法·leetcode
YuTaoShao3 小时前
【LeetCode 热题 100】56. 合并区间——排序+遍历
java·算法·leetcode·职场和发展
二进制person7 小时前
Java SE--方法的使用
java·开发语言·算法