leetcode:152. 乘积最大子数组

152. 乘积最大子数组

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

子数组 是数组的连续子序列。

示例 1:

输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例 2:

输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

提示:

  • 1 <= nums.length <= 2 ∗ 1 0 4 2 * 10^4 2104
  • -10 <= nums[i] <= 10
  • nums 的任何前缀或后缀的乘积都 保证 是一个 32-位 整数

解法

  • 动态规划:四个步骤:
    • 问题定义
    • 状态转移方程
    • 初始条件和边界情况
    • 确定计算顺序(自顶向下,还是自下向上)

问题定义:
连续乘积的最大子数组,如果借鉴最大子数组和的思路做是有问题,因为乘积涉及到正负问题,负负得正。两个大的负数相乘得到的值可能大于当前的正数。因此这里需要保留每个状态下的最大值和最小值。min_dp[i]表示以i结尾的时候的最小连续乘积,max_dp[i]表示以i结尾的时候的最大连续乘积;

状态转移方程:

  • min_dp[i] = min(min_dp[i-1] * nums[i], max_dp[i-1] * nums[i], nums[i])
  • max_dp[i] = max(min\_dp[i-1] * nums[i], max_dp[i-1] * nums[i], nums[i])

初始化条件和边界条件

  • min_dp[0] = nums[0]
  • max_dp[0] = nums[0]

确定计算顺序:
这个是从下向上的方向计算即可

代码实现

动态规划

python实现

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        
        min_dp = [0] * n
        max_dp = [0] * n
        min_dp[0] = nums[0]
        max_dp[0] = nums[0]
        for i in range(1, n):
            min_dp[i] = min(min_dp[i-1]*nums[i], max_dp[i-1]*nums[i], nums[i])
            max_dp[i] = max(min_dp[i-1]*nums[i], max_dp[i-1]*nums[i], nums[i])
        return max(max_dp)

c++实现

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        if (n == 1) return nums[0];

        vector<int> min_dp (n, 0);
        min_dp[0] = nums[0];
        vector<int> max_dp (n, 0);
        max_dp[0] = nums[0];
        for (int i=1; i<n; i++) {
            min_dp[i] = min(min_dp[i-1] * nums[i], min(max_dp[i-1] * nums[i], nums[i]));
            max_dp[i] = max(min_dp[i-1] * nums[i], max(max_dp[i-1] * nums[i], nums[i]));
        }
        return *max_element(max_dp.begin(), max_dp.end());
    }
};

复杂度分析

  • 时间复杂度: O ( N ) O(N) O(N)
  • 空间复杂度: O ( N ) O(N) O(N)

动态规划优化成两个值

由于状态的改变只与前一个元素的最小值和最大值有关,我们只需要保存最近的元素状态的最大值和最小值即可,以及一个最大值
python实现

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        
        max_dp = nums[0]
        min_dp = nums[0]
        ans = nums[0]
        for i in range(1, n):
            mx = max_dp
            mn = min_dp
            max_dp = max(mx * nums[i], mn * nums[i], nums[i])
            min_dp = min(mx * nums[i], mn * nums[i], nums[i])
            ans = max(ans, max_dp)
        return ans

c++实现

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        if (n == 1) return nums[0];
        int max_dp = nums[0], min_dp = nums[0], ans = nums[0];
        for (int i=1; i<n; i++) {
            int mx = max_dp, mn = min_dp;
            max_dp = max(mx * nums[i], max(mn * nums[i], nums[i]));
            min_dp = min(mx * nums[i], min(mn * nums[i], nums[i]));
            ans = max(ans, max_dp);
        }
        return ans;
    }
};

注意参数更新,需要中间变量。否则前一个的更新会导致后一个值的更新不对,不是前一个状态的值。

复杂度分析

  • 时间复杂度: O ( N ) O(N) O(N)
  • 空间复杂度: O ( 1 ) O(1) O(1)

参考

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...