题目:给你一个整数数组 nums
,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
电脑终于修好了,niiiiiiice
这道题一开始是没有任何思路的,然后去把相关题目"最大子序和"、“除自身意外的数组的乘积”、”打家劫舍“、”三个数的最大乘积“分别做了一遍,饶了一圈回来感觉这就是道动态规划题,和”53 最大子序和“很像,难点就是方程建立时负数的处理上。最大子序和如果f[i-1]小于0可以直接扔掉,因为对结果是负增益;但是对于这道题来说,如果f[i-1]小于零,在后续遍历中乘以一个负数是可以变成正数的,因此如果更新的时候单纯取当前最大值可能会陷入局部最优,比如[2,-4,8,-1]中,最大值策略输出会是8,但是真正结果应该是64。
联系到”628 三个数的最大乘积“的官方题解2,想到可以维护三个值,分别记录当前连续乘积最大值()、连续乘积最小值()和最终结果(answer),更新规则如下:
其中n就是nums[i],把最小值(一般是负数)和最大值分别记录,也就是记录两个绝对值最大的,这样更新的话就可以避免上面说的局部最优,最终返回answer即可。
代码实现:
#define max3(a,b,c) (a>b?a:b)>c?(a>b?a:b):c
#define min3(a,b,c) (a<b?a:b)<c?(a<b?a:b):c
#define max(a,b) a>b?a:b
int maxProduct(int* nums, int numsSize){
int minAns=nums[0],maxAns=nums[0],ans=nums[0];
int i;
for(i=1;i<numsSize;i++){
int tmp=minAns;
minAns=min3(minAns*nums[i],maxAns*nums[i],nums[i]);
maxAns=max3(maxAns*nums[i],tmp*nums[i],nums[i]);
ans=max(ans,maxAns);
}
return ans;
}
这里有一个细节就是对minAns和maxAns更新时,先更新的那一个必须先保存原来的值,否则更新规则会错误,以代码中为例,如果不用tmp保存minAns,更新规则就是,
的更新显然是不对的
运行结果: