子数组最大乘积【刷题记录】

一 题目描述
给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积。
示例1
输入:[-2.5,4,0,3,0.5,8,-1]
返回值:12.0000

二 解题思路

(一) 动态规划

对于本题要求解子数组的最大乘积,参考求解子数组最大和的思想,将状态转移方程改为:
在这里插入图片描述

其中mx是当前状态的最大值,mn是当前状态的最小值。因为本题目是求解子数组最大乘积,我们考虑到负数乘负数得到正数,此时有可能会比连续正数相乘的值大,所以我们记录每个状态的最大值和最小值,并且和当前arr[i]的值进行对比,最终得到子数组的最大乘积。(和子数组最大累加和进行对比学习!!!)
在这里插入图片描述

class Solution:
    def maxProduct(self , arr ):
        # write code here
        # 初始化 最大 最小 dp数组
        dp_max = [1.0] * len(arr)
        dp_min = [1.0] * len(arr)
        # 赋初值
        dp_max[0] = arr[0]
        dp_min[0] = arr[0]
        total = arr[0]
        for i in range(1, len(arr)):
            dp_max[i] = max(arr[i], dp_max[i-1] * arr[i], dp_min[i-1] * arr[i])
            dp_min[i] = min(arr[i], dp_min[i-1] * arr[i], dp_max[i-1] * arr[i])
            total = max(total , dp_max[i])
        return total

或者!!!更推荐!!!

由于负数的存在,会导致乘法结果反转。dp[i-1]a[i]反倒变成了最小值。
沿着乘法的特性看,如果a[i]为负数,那么dpa[i]时,dp越大结果越小。dp越小结果越大。所以,我们只需要同时保存最大值和最小值,就可以写出状态转移方程了。

a[i] > 0时:
max_dp[i] = max(a[i], a[i]*max_dp[i-1])
min_dp[i] = min(a[i],a[i]*min_dp[i-1])

a[i] < 0时:
max_dp[i] = max(a[i], a[i]*min_dp[i-1])
min_dp[i]= min(a[i], a[i]*max_dp[i-1])
在这里插入图片描述
a[i]=0时,max和min肯定是0。

class Solution:
    def maxProduct(self , arr ):
        # write code here
        # 初始化 最大 最小 dp数组
        max_dp = [1.0]*len(arr)
        min_dp = [1.0]*len(arr)
        # 赋初值
        min_dp[0] = arr[0]
        max_dp[0] = arr[0]
        total = arr[0]
        for i in range(1, len(arr)):
            if arr[i] > 0:
                # 正*= 正
                max_dp[i] = max(arr[i], max_dp[i-1]*arr[i])
                # 负*= 负
                min_dp[i] = min(arr[i], min_dp[i-1]*arr[i])
            else:
                # 负*=正
                max_dp[i] = max(arr[i], min_dp[i-1]*arr[i])
                # 正*=负
                min_dp[i] = min(arr[i], max_dp[i-1]*arr[i])
            total = max(total, max_dp[i])
        return total

复杂度分析
时间复杂度:循环一层,时间复杂度为O(n)
空间复杂度:没有引入额外的地址空间,空间复杂度为O(1)

(二) 暴力法

对于求解子数组的最大乘积,只需要按照子数组的大小,进行遍历,最后记录最大乘积,输出结果即可

1、只包含一个元素,直接返回该元素;
2、包含两个或两个以上元素,暴力循环求乘积最大的连续子数组,返回乘积。

class Solution:
    def maxProduct(self , arr ):
        # write code here
        # 整数数组 nums 只包含一个元素
        if len(arr) == 1:
            return float(arr[0])
        # 记录整数数组 arr 中乘积最大的连续子数组的乘积
        maxres = arr[0]
        for i in range(len(arr)):
            # curmax 记录整数数组 arr 中当前乘积最大的连续子数组的乘积
            curmax = 1
            for j in range(i, len(arr)):
                curmax *= arr[j]
                # 不断更新 arr 中乘积最大的连续子数组的乘积 maxres
                maxres = max(maxres, curmax)
        return float(maxres)

复杂度分析

时间复杂度O(n x n):N表示数组的长度,两遍循环时间O(n x n)
空间复杂度O(1):仅使用常数级空间变量

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值