🟢 题目速览
LeetCode 152. 乘积最大子数组
给你一个整数数组nums,
找出乘积最大的非空连续子数组,返回这个最大乘积。
⚠️ 注意:
必须是连续的
答案保证在 32-bit 整数范围内
单个元素也算子数组
示例
输入:nums = [2,3,-2,4] 输出:6 解释:[2,3] 的乘积最大输入:nums = [-2,0,-1] 输出:0🧠 我的第一反应(又踩坑了)
看到“最大子数组”,大脑秒回Kadane 算法:
maxEndingHere = max(nums[i], maxEndingHere + nums[i])❌ 直接套用 → 错得离谱
原因只有一个字:
负 × 负 = 正
🚨 核心难点
在加法里:
前面是负数 → 直接丢掉
但在乘法里:
一个很小的负数
可能遇到另一个负数
瞬间变成最大值
👉最小值可能变成最大值
✅ 正确思路:同时维护最大 & 最小
定义两个变量:
maxProd:以当前位置结尾的最大乘积minProd:以当前位置结尾的最小乘积
状态转移:
tempMax = max(nums[i], maxProd * nums[i], minProd * nums[i]) tempMin = min(nums[i], maxProd * nums[i], minProd * nums[i])✨ 最优解代码(面试版)
class Solution { public int maxProduct(int[] nums) { int maxProd = nums[0]; int minProd = nums[0]; int ans = nums[0]; for (int i = 1; i < nums.length; i++) { int tempMax = Math.max( nums[i], Math.max(maxProd * nums[i], minProd * nums[i]) ); int tempMin = Math.min( nums[i], Math.min(maxProd * nums[i], minProd * nums[i]) ); maxProd = tempMax; minProd = tempMin; ans = Math.max(ans, maxProd); } return ans; } }🔍 执行过程拆解
以nums = [2,3,-2,4]为例:
i | nums[i] | maxProd | minProd | ans |
|---|---|---|---|---|
0 | 2 | 2 | 2 | 2 |
1 | 3 | 6 | 3 | 6 |
2 | -2 | -2 | -12 | 6 |
3 | 4 | 4 | -48 | 6 |
✅ 最终答案:6
⚡ 为什么这题是 Hot100 必刷
Kadane 算法的升级版
负数处理极具代表性
面试高频(字节 / 阿里 / 拼多多)
衍生题极多(最大和、环形数组、二维)
🎯 我学到的东西
在乘法世界里,最小值和最大值永远在一起。
你不是在选路径,
而是在防止“最坏情况变成最好情况”。
⚠️ 易错点总结
错误 | 正确 |
|---|---|
只维护最大值 | 必须同时维护最小值 |
忽略 0 | 0 会重置整个状态 |
用加法 DP | 这是乘法问题 |
用排序 | 子数组必须连续 |
🧩 一句话总结
乘法的最大子数组,必须在“最好”和“最坏”之间反复横跳。
🎤 面试收尾(建议直接背)
“这道题是经典 Kadane 算法的变形。
由于负数的存在,最大值可能来自最小值乘以负数,
因此我们需要同时维护以当前位置结尾的最大值和最小值。
时间复杂度 O(n),空间复杂度 O(1)。”