152.乘积最大子数组

【LetMeFly】152.乘积最大子数组:dp + 原地滚动

力扣题目链接:https://leetcode.cn/problems/maximum-product-subarray/

给你一个整数数组 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 * 104
  • -10 <= nums[i] <= 10
  • nums 的任何前缀或后缀的乘积都 保证 是一个 32-位 整数

方法一:dp + 原地滚动

需要两个变量$m$和$M$,分别表示以当前处理到的数字为结尾的乘积最大子数组

初始值$m$和$M$都是数组中第一个元素nums[0]

$i$从下标1开始遍历数组,既然要以下标$i$为连续数组的结尾,那么就有三种选择:

  1. 只选择当前这个下标为$i$的元素($nums[i]$)
  2. 使用以上一个元素结尾的子数组的最大乘积 乘上 这个元素($nums[i] * M$)
  3. 使用以上一个元素结尾的子数组的最小乘积 乘上 这个元素($nums[i] * m$)

每遍历到每一个元素时,计算上述三个新的可能的极值,并更新$m$和$M$,同时记录一下整个遍历过程中答案的最大值即可。

Q&S: 为什么还要记录最小值$m$而不是仅仅记录最大值$M$?

因为最大值可能由两个负数相乘得到。如果是两个负数相乘的话,负数越小乘积越大。

  • 时间复杂度$O(n)$,其中$n$是数组nums中元素的个数
  • 空间复杂度$O(1)$

AC代码

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int maxProduct(vector<int>& nums) {
int ans = nums[0];
int m = nums[0], M = nums[0];
for (int i = 1; i < nums.size(); i++) {
int timesLastm = m * nums[i];
int timesLastM = M * nums[i];
m = min(nums[i], min(timesLastm, timesLastM));
M = max(nums[i], max(timesLastm, timesLastM));
ans = max(ans, M);
}
return ans;
}
};

运行结果还可以

同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/126094071


152.乘积最大子数组
https://blog.letmefly.xyz/2022/08/01/LeetCode 0152.乘积最大子数组/
作者
Tisfy
发布于
2022年8月1日
许可协议