152. 乘积最大子数组(中等)
题目
给定一个整数数组 nums,在它的非空连续子数组(连续的一段,至少含一个数)里,找出所有元素相乘所得最大的那个,并返回这个乘积。
注意两点:子数组必须连续,不能跳着挑;单独一个数也算子数组,乘积就是它自己。
自造示例:[1,-2,3,-4,0,2] → 24。最大的是 [1,-2,3,-4],乘积 1 × (-2) × 3 × (-4) = 24。
约束:数组长度 1 ~ 2 × 104;元素范围 -10 ~ 10;任意子数组的乘积保证是 32 位整数。
思路
一句话:对于“以当前位置结尾的子数组”,同时记录它能得到的最大乘积和最小乘积,负数一来就“正负互换”。
先想最直白的:枚举所有起点 i、终点 j,再把这一段乘起来。最差要 O(n³);即使用“边扫边乘”优化成 O(n²),n 最大 2 × 104,也跑不动。
关键观察:乘积不是求和,乘一个负数会把符号翻过来。比如到 i 结尾,最大的乘积不一定来自“之前的最大”,还可能来自“之前的最小”——一个很负的数乘负数反而变大。所以只看一个最大值会丢信息。
因此每个位置维护两个状态:curMax = 以当前元素结尾的子数组的最大乘积,curMin = 最小乘积。下一步在「接上 curMax、接上 curMin、直接从当前元素另起炉灶」三者里取最大 / 最小。这样一次遍历就能搞定。
解法
状态:curMax[i] / curMin[i] 分别表示必须以 nums[i] 结尾的子数组的最大 / 最小乘积。
转移(对当前数 n):
fromMax = curMax × n(接上最大)fromMin = curMin × n(接上最小)curMax = max(n, fromMax, fromMin)—— 其中n表示从当前位置新开子数组curMin = min(n, fromMax, fromMin)- 用
curMax更新答案。
因为当前状态只依赖上一步,两个变量滚动即可。
| 当前数 | 接 curMax (×n) | 接 curMin (×n) | 新 curMax | 新 curMin | 答案 |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 | 1 |
| -2 | -2 | -2 | -2 | -2 | 1 |
| 3 | -6 | -6 | 3 | -6 | 3 |
| -4 | -12 | 24 | 24 | -12 | 24 |
| 0 | 0 | 0 | 0 | 0 | 24 |
| 2 | 0 | 0 | 2 | 0 | 24 |
看第 4 行:接最大得到 -12,但“接最小”反而得到 24,这就是必须保留最小值的理由。
下图把上面 5 个步骤串成流程,并逐步演示:


C++
#include <algorithm>
#include <vector>
using namespace std; class Solution {
public:
int maxP本篇为付费内容
您已阅读试读部分,购买后即可解锁全文。
⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。
还没有评论,来说两句?