152. 乘积最大子数组(中等)

Blind 75 › 152. 乘积最大子数组(中等) (第 8 章)
文章工具

题目

给定一个整数数组 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答案
111111
-2-2-2-2-21
3-6-63-63
-4-122424-1224
0000024
2002024

看第 4 行:接最大得到 -12,但“接最小”反而得到 24,这就是必须保留最小值的理由。

下图把上面 5 个步骤串成流程,并逐步演示:

152. 乘积最大子数组(中等) 解法步骤流程图
图① 解法步骤流程图(共 5 步)。
152. 乘积最大子数组(中等) 按步骤逐步执行的动画
动图② 按步骤依次推进(循环播放)。

C++

C++ 片段需补全 main() 函数才能运行在实训台打开 →
#include <algorithm>
#include <vector>
using namespace std;  class Solution {
public:
 int maxP

🔒

本篇为付费内容

您已阅读试读部分,购买后即可解锁全文。

⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。