連續子陣列的最大和

2020-10-06 12:00:51

問題描述:求下標 0-n 的連續子陣列的最大和

假設陣列下標: 0... i . . . j . . . n 0...i...j...n 0...i...j...n
區間 [ i , j ] [i,j] [i,j]是最大和 maxsum

maxsum有2種情況

1.假設 maxsum<= 0; 只有一種情況,所有數都為非正數. 如果 a [ x ] > 0 a[x] >0 a[x]>0,那麼假設不成立。

maxsum = max(maxsum,a[x]);(即找最大的負數)

2.假設 maxsum>0;那麼

a[x] <= maxsum; 並且 a[i] >= 0, a[j] >= 0;(如果a[i]<0,那麼不選i,能讓maxsum變大,與假設矛盾)

最大和為 從非負數開始 到非負數結束

阻止區間向兩邊擴充套件的條件。
1.到頭了。(即到達左右邊界,沒有元素了)
2.左邊。從 i − 1 + i − 2 + . . . + k < 0 , ( 0 ≤ k ≤ i − 1 ) i-1+i-2+...+k <0,(0 \leq k \leq i-1) i1+i2+...+k<0,(0ki1).(從i-1開始,向左累加,找不到非負數和了).
右邊。從 j + 1 + j + 2 + . . . + n < 0 , j+1+j+2+...+n <0, j+1+j+2+...+n<0,.(從j+1開始,向右累加,找不到非負數和了).

我們從左到右遍歷,那麼左邊利用無法擴充套件(第2條),右邊利用到頭了。

如何確定區間 [i,j]

假設我們找到 一個正數, 下標 m,設 T = n − 1 + n − 2 + . . . + m n-1+n-2+...+m n1+n2+...+m
1.右邊 是正數,那麼累加。 (T > 0)
2.右邊 是非負數, 假設下標 n

1.如果 T < 0,這一塊已經無法擴充套件了,必須重新尋找下一個區間。
2.T == 0, 加和沒加一樣了
3.如果 T > 0, 是否存在 m<s<n, 使得 a s + . . . + a n > a m + . . . + a s + . . . + a n a_s+...+a_n > a_m + ...+a_s + ...+ a_n as+...+an>am+...+as+...+an
假設條件成立,那麼
a m + . . . + a s − 1 < 0 a_m + ... + a_{s-1} < 0 am+...+as1<0,這是不存在的, 處理第一條時,已經處理完畢。

也就是說 從一個正數開始 , 當 和 大於0 時,最大和在 當前區間內(正數下標開頭)或者 不在當前區間,
不會出現 最大和的開始下標, 出現在 當前區間中間的部分。

程式碼:

int maxSubArray(vector<int>& nums) {
        static auto speedup = [](){ios::sync_with_stdio(false);cin.tie(nullptr);return nullptr;}();
        if(nums.size() == 0) return 0;
        int sum = 0,res = INT_MIN;
        for(int i = 0;i<nums.size();++i){
            sum+= nums[i];
            res = max(sum,res);
            //sum 就是 T,利用sum = 0,代替 重新尋找區間
            if(sum<0){
                sum = 0;
            }
        }
        return res;
    }