最大連續區間和問題 —— 轉自purplest C++博客

    今天正好做到一道有關"最大子矩陣問題"的題目,可以分解成最大連續區間和問題。看到這篇文章不錯,順便轉載過來。

    原文地址: http://www.cppblog.com/purplest/archive/2013/03/04/198199.html, 轉載請說明出處

 

最大連續區間和是一個經典的問題。給定一個長度爲n的序列a[1],a[2]...a[n-1],a[n],求一個連續的子序列a[i],a[i+1]...a[j-1],a[j],使得a[i]+a[i+1]...a[j-1]+a[j]最大。

 

①最簡單最容易想到的就是根據定義來枚舉。

枚舉上下界{i,j | 0<=i<=j<=n},維護一個max值即可。

其中枚舉上下界的時間複雜度爲O(n^2),求區間和的複雜度爲O(n),所以總時間複雜度爲O(n^3)。

for ( int i = 1 ; i <= n ; i++ )
    for ( int j = i ; j <= n ; j++ )
        ans = max(ans,accumulate(a+i,a+j+1,0));

 

②其實就是第一種方法的優化。

這裏有個很容易想到的優化,即預處理出前綴和sum[i]=a[0]+a[1]+...+a[i-1]+a[i],算區間和的時候即可將求區間和的複雜度降到O(1),枚舉上下界的複雜度不變,所以總時間複雜度爲O(n^2)。

for ( int i = 1 ; i <= n ; i++ )
    sum[i]=sum[i-1]+a[i];

for ( int i = 1 ; i <= n ; i++ )
    for ( int j = i ; j <= n ; j++ )
        ans = max(ans,sum[j]-sum[i-1]);

 

③可以利用動態規劃的思維來繼續優化,得到一個線性的算法,也是最大連續區間和的標準算法

定義maxn[i]爲以i爲結尾的最大連續和,則很容易找到遞推關係:maxn[i]=max{0,maxn[i-1]}+a[i]。

所以只需要掃描一遍即可,總時間複雜度爲O(n)。

for ( int i = 1 ; i <= n ; i++ )
{
    last = max(0,last)+a[i];
    ans = max(ans,last);
}

 

④同樣用到類似的思維。

首先也需要預處理出前綴和sum[i],可以推出ans=max{sum[i]-min{sum[j] } | 0<=j<i<=n }。

而最小前綴和可以動態維護,所以總時間複雜度爲O(n)。

for ( int i = 1 ; i <= n ; i++ )
    sum[i]=sum[i-1]+a[i];

for ( int i = 1 ; i <= n ; i++ )
{
    ans = max(ans,sum[i]-minn);
    minn = min(minn,sum[i]);
}

 

總結:雖然樸素的O(n^3)和前綴和優化的O(n^2)算法很容易想到,但代碼實現卻反而比方法三麻煩,第四個方法雖然有和方法三相同的複雜度,但需要一個預處理和多出的O(n)的空間,所以,方法三很好很強大。

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