最大子段和詳解

2021-09-22 21:00:02 字數 2845 閱讀 5909

最大子段和問題(maximum interval sum)

(有時也稱lis)

經典的動態規劃問題,幾乎所有的演算法教材都會提到.本文將分析最大子段和問題的幾種不同效率的解法,以及最大子段和問題的擴充套件和運用.

一.問題描述

給定長度為n的整數序列,a[1…n], 求[1,n]某個子區間[i , j]使得a[i]+…+a[j]和最大.或者求出最大的這個和.例如(-2,11,-4,13,-5,2)的最大子段和為20,所求子區間為[2,4].

二. 問題分析

1.窮舉法

窮舉應當是每個人都要學會的一種方式,這裡實際上是要窮舉所有的[1,n]之間的區間,所以我們用兩重迴圈,可以很輕易地做到遍歷所有子區間,乙個表示起始位置,乙個表示終點位置.**如下:

int start = 0

;//起始位置

int end = 0; //結束位置

int max = 0;

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

} }

這個演算法是幾乎所有人都能想到的,它所需要的計算時間是o(n^3).當然,這個**還可以做點優化,實際上我們並不需要每次都重新從起始位置求和加到終點位置.可以充分利用之前的計算結果.

或者我們換一種窮舉思路,對於起點 i,我們遍歷所有長度為1,2,…,n-i+1的子區間和,以求得和最大的乙個.這樣也遍歷了所有的起點的不同長度的子區間,同時,對於相同起點的不同長度的子區間,可以利用前面的計算結果來計算後面的.

比如,i為起點長度為2的子區間和就等於長度為1的子區間的和+a[i+1]即可,這樣就省掉了乙個迴圈,計算時間複雜度減少到了o(n^2).**如下:

int start = 0

;//起始位置

int end = 0;//結束位置

int max = 0;

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

} }

2.分治法

求子區間及最大和,從結構上是非常適合分治法的,因為所有子區間[start, end]只可能有以下三種可能性:

在[1, n/2]這個區域內

在[n/2+1, n]這個區域內

起點位於[1,n/2],終點位於[n/2+1,n]內

以上三種情形的最大者,即為所求. 前兩種情形符合子問題遞迴特性,所以遞迴可以求出. 對於第三種情形,則需要單獨處理. 第三種情形必然包括了n/2和n/2+1兩個位置,這樣就可以利用第二種窮舉的思路求出:

以n/2為終點,往左移動擴張,求出和最大的乙個left_max

以n/2+1為起點,往右移動擴張,求出和最大的乙個right_max

left_max+right_max是第三種情況可能的最大值

示例:

int maxinterval(int *a, int left, int right)  

//center+1開始向右移動

sum = 0;

int right_max = 0;

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

int ret = left_max+right_max;

if(ret < leftmaxinterval)

ret = leftmaxinterval;

if(ret < rightmaxinterval)

ret = rightmaxinterval;

return ret;

}

分治法的難點在於第三種情形的理解,這裡應該抓住第三種情形的特點,也就是中間有兩個定點,然後分別往兩個方向擴張,以遍歷所有屬於第三種情形的子區間,求的最大的乙個,如果要求得具體的區間,稍微對上述**做點修改即可. 分治法的計算時間複雜度為o(nlogn).

3.動態規劃法

動態規劃的基本原理這裡不再贅述,主要討論這個問題的建模過程和子問題結構.時刻記住乙個前提,這裡是連續的區間

令b[j]表示以位置 j 為終點的所有子區間中和最大的乙個

子問題:如j為終點的最大子區間包含了位置j-1,則以j-1為終點的最大子區間必然包括在其中

如果b[j-1] >0, 那麼顯然b[j] = b[j-1] + a[j],用之前最大的乙個加上a[j]即可,因為a[j]必須包含

如果b[j-1]<=0,那麼b[j] = a[j] ,因為既然最大,前面的負數必然不能使你更大

對於這種子問題結構和最優化問題的證明,可以參考演算法導論上的「剪下法」,即如果不包括子問題的最優解,把你假設的解粘帖上去,會得出子問題的最優化矛盾.證明如下:

令a[x,y]表示a[x]+…+a[y] , y>=x

假設以j為終點的最大子區間 [s, j] 包含了j-1這個位置,以j-1為終點的最大子區間[ r, j-1]並不包含其中

即假設[r,j-1]不是[s,j]的子區間

存在s使得a[s, j-1]+a[j]為以j為終點的最大子段和,這裡的 r != s

由於[r, j -1]是最優解, 所以a[s,j-1]

int

max = 0;

int b[n+1];

int start = 0;

int end = 0;

memset(b,0,n+1);

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

else

if(b[i]>max)

max = b[i];

}

動態規劃法的計算時間複雜度為o(n),是最優的解。做幾道題加深理解

最直白的lis題:

最大子段和公升級版,最大m段和:

最大子段和詳解

問題的提出 給定n個整數 可能為負數 組成的序列a 1 a 2 a 3 a n 求該序列如a i a i 1 a j 的子段和的最大值。當所給的整均為負數時定義子段和為0,依此定義,所求的最優值為 max,1 i j n 例如,當 a1,a2,a3,a4,a4,a6 2,11,4,13,5,2 時,...

最大子段和問題 詳解(C

最大子段和或稱為最大部分和 maximum subtotal 問題,以下簡稱ms。舉例說明 例如 暴力破解 brute force 可以從串的任意位置開始在連續的任意位置結束,一層迴圈控制起始位置,一層迴圈控制結束位置。複雜度 o n 2 迭代 include include using names...

最大子段和

設a 是n個整數的序列,稱為該序列的子串行,其中1 i j n.子串行的元素之和稱為a的子段和.例如,a 2,11,4,13,5,2 那麼它的子段和是 長度為1的子段和 2,11,4,13,5,2 長度為2的子段和 9,7,9,8,7 長度為3的子段和 5,20,4,6 長度為4的子段和 18,15...