方法:动态规划
①确定状态:
maxP[i]表示以nums[i]结尾的最大子数组乘积;
minP[i]表示以nums[i]结尾的最小子数组乘积;
②转移方程:
maxP[i] = Math.max(nums[i], Math.max(maxP[i - 1] * nums[i], minP[i - 1] * nums[i]));
minP[i] = Math.min(nums[i], Math.min(minP[i - 1] * nums[i], maxP[i - 1] * nums[i]));
③初始条件和边界情况:maxP[i] = nums[0],minP[i] = nums[0];
④计算顺序:因为maxP[i],minP[i]由maxP[i-1],minP[i-1]推出,所以从小到大遍历。
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
//定义两个状态:
//maxP[i]表示以nums[i]结尾的最大子数组乘积
//minP[i]表示以nums[i]结尾的最小子数组乘积
int[] maxP = new int[n];
maxP[0] = nums[0];
int[] minP = new int[n];
minP[0] = nums[0];
int ans = nums[0];
for (int i = 1; i < n; i++) {
//使得maxP[i]最大(可能为nums[i]本身),
//1.考虑nums[i]为正数,与之前的最大乘积相乘,
//2.考虑nums[i]为负数,与之前的最小乘积相乘。
maxP[i] = Math.max(nums[i], Math.max(maxP[i - 1] * nums[i], minP[i - 1] * nums[i]));
//使得minP[i]最小(可能为nums[i]本身),
//1.考虑nums[i]为正数,与之前的最小乘积相乘,
//2.考虑nums[i]为负数,与之前的最大乘积相乘。
minP[i] = Math.min(nums[i], Math.min(minP[i - 1] * nums[i], maxP[i - 1] * nums[i]));
ans = Math.max(ans, maxP[i]);
}
return ans;
}
}
注意:与最大子数组和的区别在于——由于存在负数,会导致最大的变最小的,最小的变最大的,因此还需要维护当前乘积的最小值。