最大子串行和問題

2022-03-23 17:01:48 字數 2831 閱讀 7884

[question]:給定整數\(a_1,a_2,a_3,...,a_n\)(可能有負數),求\(\sum_^a_k\)的最大值(方便起見,若所有整數為負數,則最大序列和為0)

//例如:輸入\(-2,11,-4,13,-5,-2\),答案為\(20\)(從\(a_2\)到\(a_4\))

解法①:窮舉法

外兩層迴圈遍歷陣列,確定序列上下界。最內層迴圈遍歷序列求和。

1/*2

* maxsubsum1:解法①,窮舉法

3* 輸入陣列a

4* 返回最大子串行和5*/

6int maxsubsum1( const vector &a )722

}2324return

maxsum;

25 }

顯然,此方法時間複雜度為\(o(n^3)\),並沒有什麼實際意義,\(n\)取較大值時演算法效果很差。   

解法②:改進窮舉法

第二層每次迴圈順便求出子串行值,並判斷結果,取消第三層迴圈。

1/*2

* maxsubsum2:解法②,改進窮舉法

3* 輸入陣列a

4* 返回最大子串行和5*/

6int maxsubsum2( const vector &a )721

}2223return

maxsum;

24 }

顯然,此方法時間複雜度為\(o(n^2)\),在窮舉法的基礎上稍作改進,\(n\)取較大值時演算法效果仍然很差。 

解法③:分治策略

將原問題分成兩個大致相等的子問題,然後遞迴的對他們求解。最大子串行可能出現的地方:輸入資料的左半部,輸入資料的右半部,跨越資料中部佔據左右兩半部分。

1/*2

* max3:遞迴函式

3* 輸入陣列a,遞迴下界,遞迴上界

4* 返回一次遞迴最大子串行和5*/

6int maxsumrec(const vector &a, int left, int

right)715

16int center = (left + right) / 2;17

int maxleftsum =maxsumrec(a, left, center);

18int maxrightsum = maxsumrec(a, center + 1

, right);

1920

int maxleftbordersum = 0, leftbordersum = 0;21

for (int i = center; i >= left; i--)

22//

前半部分最大子串行和

2728

int maxrightbordersum = 0, rightbordersum = 0;29

for (int j = center + 1; j <= right; j++)

30//

後半部分最大子串行和

3536

return max3(maxleftsum, maxrightsum, maxleftbordersum + maxrightbordersum);//

max3為求三個整型數的最大值函式37}

3839

/*40

* maxsubsum3:解法③,分治策略

41* 輸入陣列a

42* 返回最大子串行和

43*/

44int maxsubsum3( const vector &a )

45

由於使用了遞迴,且遞迴函式內使用了一層迴圈,所以演算法時間複雜度為\(o(nlog_2n)\)。此時已經為較理想的結果。  

解法④:終極方法

再次改進窮舉法,顯然我們可以推出乙個結論,如果\(a[i]\)是負的,那麼它不可能代表最優序列的起點,因為任何包含\(a[i]\)的作為起點的子串行都可以通過用\(a[i+1]\)做起點而得到改進。類似地,任何負的

子串行不可能是最優子串行的字首。如果在內迴圈中檢測到\(a[i]\)到\(a[j]\)的子串行是負的,那麼我們可以推進\(i\)。關鍵結論是:我們不僅可以把\(i\)推進到\(i+1\),而且我們實際上還可以把它一直推進到\(j+1\)。為了證明,我們由前面的結論知道\(a[i]\)是非負的,其次\(j\)是使從下標\(i\)開始使序列和為負的第乙個下標,令\(p\)為\(i+1\)到\(j\)之間的任一下標,那麼從下標\(i\)到\(j\)中,序列\(a[i]...a[p-1]\)的和始終大於序列\(a[p]...a[j]\)的和。因此把\(i\)推進到\(j+1\)是安全的,我們不會錯過最優解。

1/*2

* maxsubsum4:解法④,終極方法

3* 輸入陣列a

4* 返回最大子串行和5*/

6int maxsubsum4( const vector &a )721

22return

maxsum;

23 }

顯然,演算法的時間複雜度為\(o(n)\),並且只對資料一次掃瞄,一旦\(a[i]\)被讀入並處理,它就不需要被記憶,因此僅需常量空間並以線性時間執行的聯機演算法

總結:要善於思考問題的結構,仔細研究資料的結構尋找最優解法。沒有思路時也可以先寫出最笨的方法,然後逐步改進。

參考:資料結構與演算法分析(c++描述).第三版.【美】mark allen weiss.人民郵電出版社

最大子串行和問題

問題 給定一整數序列a1,a2,an 可能有負數 求a1 an的乙個子串行ai aj,使得ai到aj的和最大 例如 整數序列 2,11,4,13,5,2,5,3,12,9的最大子串行的和為21。對於這個問題,最簡單也是最容易想到的那就是窮舉所有子串行的方法。利用三重迴圈,依次求出所有子串行的和然後取...

最大子串行和問題

問題描述 給定乙個整數序列 可能有負數 求一子串行 記為l 使得該子串行所有元素之和最大。例 給定序列 2,11,4,13,5,2,則最大子串行和為20 11,4,13 方法一 遍歷窮舉 o n 2 略方法二 分治遞迴 o n logn 思路 將輸入序列l分為左右兩個子串行l1和l2,則l 只可能以...

最大子串行和問題

問題描述 求 2,11,4,13,5,2 的最大子串行和。方法一 使用3層for迴圈巢狀,窮舉式的嘗試所有的可能,如下 public class demo1 return maxsum public static void main string args system.out.println 最大...