2020-05-18 LeetCode 152 乘積最大子數組 c

題目:給你一個整數數組 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,想到可以維護三個值,分別記錄當前連續乘積最大值(fminf_{min})、連續乘積最小值(fmaxf_{max})和最終結果(answer),更新規則如下:
fmin[i]=min[fmin[i1]ni,fmax[i1]ni,ni]fmax[i]=max[fmax[i1]ni,fmax[i1]ni,ni]answer=max[answer,fmax[i]] f_{min}[i]=min[f_{min}[i-1]*n_i,f_{max}[i-1]*n_i,n_i] \\ f_{max}[i]=max[f_{max}[i-1]*n_i,f_{max}[i-1]*n_i,n_i] \\ answer=max[answer,f_{max}[i]]
 其中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,更新規則就是,
fmin[i]=min[fmin[i1]ni,fmax[i1]ni,ni]fmax[i]=max[fmin[i]ni,fmax[i1]ni,ni]answer=max[answer,fmax[i]] f_{min}[i]=min[f_{min}[i-1]*n_i,f_{max}[i-1]*n_i,n_i] \\f_{max}[i]=max[f_{min}[i]*n_i,f_{max}[i-1]*n_i,n_i] \\answer=max[answer,f_{max}[i]]
fmaxf_{max}的更新顯然是不對的

運行結果:
2020-05-18_114841

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章