題目:給你一個整數數組 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,更新規則就是,
的更新顯然是不對的
運行結果: