题目解析
给定一个整数数组 nums,要求找到一个连续子数组,使其乘积最大,并返回该最大乘积。
算法思路
这个问题的关键在于:
1. 负数会改变乘积的大小,可能导致最大变最小,最小变最大。
2. nums[i] 可能是正数、负数或零,每种情况的处理方式不同。
3. 需要跟踪两个变量:
• maxi:当前子数组的最大乘积
• mini:当前子数组的最小乘积(因为负数可能反转最小值为最大值)
状态转移方程:
• 如果 nums[i] 为正数:
• maxi = max(nums[i], nums[i] * maxi)
• mini = min(nums[i], nums[i] * mini)
• 如果 nums[i] 为负数:
• maxi 和 mini 互换后再计算:
• maxi = max(nums[i], nums[i] * mini)
• mini = min(nums[i], nums[i] * maxi)
最终 ans 记录全局最大乘积。
代码解析
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
int maxi = 1, mini = 1; // 维护最大值和最小值
int ans = INT_MIN; // 记录全局最大乘积
for (int i = 0; i < n; i++) {
if (nums[i] < 0) { // 负数翻转最大最小值
swap(maxi, mini);
}
maxi = max(nums[i], nums[i] * maxi); // 更新最大乘积
mini = min(nums[i], nums[i] * mini); // 更新最小乘积
ans = max(ans, maxi); // 更新全局最大乘积
}
return ans;
}
};
详细运行步骤
假设 nums = [2, 3, -2, 4],我们来看代码如何执行。
初始化
maxi = 1, mini = 1, ans = INT_MIN
第 1 轮 (i=0, nums[i]=2)
nums[i] = 2
maxi = max(2, 2 * 1) = 2
mini = min(2, 2 * 1) = 2
ans = max(INT_MIN, 2) = 2
状态:
maxi = 2, mini = 2, ans = 2
第 2 轮 (i=1, nums[i]=3)
nums[i] = 3
maxi = max(3, 3 * 2) = 6
mini = min(3, 3 * 2) = 3
ans = max(2, 6) = 6
状态:
maxi = 6, mini = 3, ans = 6
第 3 轮 (i=2, nums[i]=-2)
nums[i] = -2
负数翻转 maxi 和 mini:
swap(maxi, mini) → maxi = 3, mini = 6
maxi = max(-2, -2 * 6) = -2
mini = min(-2, -2 * 3) = -12
ans = max(6, -2) = 6
状态:
maxi = -2, mini = -12, ans = 6
第 4 轮 (i=3, nums[i]=4)
nums[i] = 4
maxi = max(4, 4 * -2) = 4
mini = min(4, 4 * -12) = -48
ans = max(6, 4) = 6
状态:
maxi = 4, mini = -48, ans = 6
最终结果
return ans = 6
复杂度分析
• 时间复杂度:O(n),遍历数组一次。
• 空间复杂度:O(1),只使用了 maxi、mini 和 ans 变量。