三種解法求 最大連續子串行的和

2021-10-09 04:24:55 字數 1912 閱讀 1359

示例:

輸入: [-2,1,-3,4,-1,2,1,-5,4]

輸出: 6

解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。

假設a[l]...a[r]的和為 sum

如果 sum > 0,則說明 sum 對結果有增益效果,則 sum 保留

如果 sum < 0,則說明 sum 對結果無增益效果,需要捨棄

明白了這個道理,那麼對於第i個數來說,我們檢視他之前的sum,如果sum<0,那麼當前的最大連續子串行和就是它本身(捨棄前面的);如果sum>0,那麼當前的最大和就是sum+a[i]  (sum保留了)

sum=0的情況都保留和丟棄都可以

int ans=a[1];  //ans初始化為第乙個元素,不能是0,因為最大值可能是負數

int sum=0;

for (int i=1; i<=n; i++)

用f[i]表示以第i個數a[i]結尾的最大子串行和。

那麼f[i]的狀態轉移方程也很好得出,對於a[i]是單獨算還是加入前面的f[i-1],即:f[i]=max(f[i-1]+a[i],a[i])

問:為什麼會想到用f[i]表示以第i個數a[i]結尾的最大子串行和?

連續的子串行的和,這是關鍵,只有f[i]包含了a[i],遞推才可以進行下去,不然就不連續了。

**:用ans代替f[i]的迭代,省空間。

int ans=a[1],sum=0;

for (int i=1; i<=n; i++)

對於乙個區間 [l, r],我們可以維護四個量:

lsum 表示 [l, r] 內以 l 為左端點的最大子段和

rsum 表示 [l, r] 內以 r 為右端點的最大子段和

msum 表示 [l, r] 內的最大子段和

isum 表示 [l, r] 的區間和

然後轉移條件,相當於線段樹:

首先最好維護的是 isum,區間 [l, r] 的 isum 就等於「左子區間」的 isum 加上「右子區間」的 isum。

對於 [l, r] 的 lsum,存在兩種可能,它要麼等於「左子區間」的 lsum,要麼等於「左子區間」的 isum 加上「右子區間」的 lsum,二者取大。

對於 [l, r] 的 rsum,同理,它要麼等於「右子區間」的 rsum,要麼等於「右子區間」的 isum 加上「左子區間」的 rsum,二者取大。

當計算好上面的三個量之後,就很好計算 [l,r] 的 msum 了。我們可以考慮 [l,r] 的 msum 對應的區間是否跨越 m——它可能不跨越 m,也就是說 [l,r] 的 msum 可能是「左子區間」的 msum 和 「右子區間」的 msum 中的乙個;它也可能跨越 m,可能是「左子區間」的 rsum 和 「右子區間」的 lsum 求和。三者取大。

線段樹的學習和使用:

class solution ;

status pushup(status l, status r) ;

};status get(vector&a, int l, int r) ;

int m = (l + r) >> 1;

status lsub = get(a, l, m);

status rsub = get(a, m + 1, r);

return pushup(lsub, rsub);

}int maxsubarray(vector& nums)

};

高階版最大連續子串行的和:

最大連續子串行和DP解法

給定乙個數字序列a1,a2,an,求i,j 1 i j n 使得ai aj最大,輸出這個最大和 暴力方法 列舉i和j的所有可能性,複雜度o n2 並且o n2 次計算ai aj,總體複雜度為o n3 就算我們採取字首和的方法,將計算複雜度降為o 1 複雜度o n2 仍然難以讓我們接受 step1 令...

求最大連續子串行的和

小王的賬本 小王出門打零工,工作很不穩定,收入也很不穩定,他找了乙個賬本記錄他每天的支出,例如 1月1日 收入320 1月2日 沒找到工作,吃飯花了30 1月3日 掙50 1月4日 無工作,吃飯花了17 1月5日 無工作,租房 吃飯花了2600 年底了,小王想知道自己賬本上哪一段時間掙錢掙的最多。剛...

求最大連續和的解法(4種)

列舉法 我們通過乙個乙個列舉長度之和來求解,例如序列列舉的情況有 1 1,2 1,2,1 2 2,1 1 通過三個迴圈來列舉這些情況 int sum 0,a 10 for int i 1 i n i 列舉每乙個數 for int j i j n j 時間複雜度 o n 3 2 遞推 對1的優化 定義...