Medium
题目描述
给你一个整数数组 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 * 10^4-10 <= nums[i] <= 10nums的任何子数组的乘积都 保证 是一个 32位 整数
解题思路
这道题是经典的动态规划问题,但与最大子数组和不同的是,乘积运算有其特殊性:
核心思路分析:
- 负数的特殊性:两个负数相乘得正数,所以我们需要同时维护最大值和最小值
- 零的影响:遇到0时乘积重置为0,需要重新开始计算
动态规划状态设计:
maxDP[i]:以nums[i]结尾的子数组的最大乘积minDP[i]:以nums[i]结尾的子数组的最小乘积
状态转移方程:
maxDP[i] = max(nums[i], maxDP[i-1] * nums[i], minDP[i-1] * nums[i])
minDP[i] = min(nums[i], maxDP[i-1] * nums[i], minDP[i-1] * nums[i])
优化思路: 由于每个状态只依赖前一个状态,可以用两个变量代替数组,将空间复杂度优化到O(1)。
算法步骤:
- 初始化最大值、最小值和结果
- 遍历数组,动态更新当前最大值和最小值
- 每次更新结果为历史最大值
这种方法能够正确处理负数、零和正数的所有组合情况。
代码实现
class Solution {
public:
int maxProduct(vector<int>& nums) {
int maxVal = nums[0];
int minVal = nums[0];
int result = nums[0];
for (int i = 1; i < nums.size(); i++) {
if (nums[i] < 0) {
swap(maxVal, minVal);
}
maxVal = max(nums[i], maxVal * nums[i]);
minVal = min(nums[i], minVal * nums[i]);
result = max(result, maxVal);
}
return result;
}
};
class Solution:
def maxProduct(self, nums: List[int]) -> int:
max_val = nums[0]
min_val = nums[0]
result = nums[0]
for i in range(1, len(nums)):
if nums[i] < 0:
max_val, min_val = min_val, max_val
max_val = max(nums[i], max_val * nums[i])
min_val = min(nums[i], min_val * nums[i])
result = max(result, max_val)
return result
public class Solution {
public int MaxProduct(int[] nums) {
int maxVal = nums[0];
int minVal = nums[0];
int result = nums[0];
for (int i = 1; i < nums.Length; i++) {
if (nums[i] < 0) {
int temp = maxVal;
maxVal = minVal;
minVal = temp;
}
maxVal = Math.Max(nums[i], maxVal * nums[i]);
minVal = Math.Min(nums[i], minVal * nums[i]);
result = Math.Max(result, maxVal);
}
return result;
}
}
var maxProduct = function(nums) {
let maxVal = nums[0];
let minVal = nums[0];
let result = nums[0];
for (let i = 1; i < nums.length; i++) {
if (nums[i] < 0) {
[maxVal, minVal] = [minVal, maxVal];
}
maxVal = Math.max(nums[i], maxVal * nums[i]);
minVal = Math.min(nums[i], minVal * nums[i]);
result = Math.max(result, maxVal);
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历数组一次,其中 n 为数组长度 |
| 空间复杂度 | O(1) | 只使用常数个额外变量存储状态 |
相关题目
. Maximum Subarray (Medium)
. House Robber (Medium)
. Product of Array Except Self (Medium)
. Subarray Product Less Than K (Medium)