計算給定陣列的最大子陣列的和有很多種演算法,最常見的是使用分治的策略,然而此問題用分治卻增加了時間複雜度和**複雜度。有更簡單的演算法,本文就將介紹乙個線性時間的迭代演算法。這應該是最高效的解決方法了。
首先**如下:
int maxsubarray( int* array, int length)
return maxarray;
}#include
using
namespace
std;
int main()
; int num = sizeof(a)/sizeof(a[0]);
int result = maxsubarray(a, num);
cout
<<"result:"
int b = ;
num = sizeof(b)/sizeof(b[0]);
result = maxsubarray(b, num);
cout
<<"result:"
return
0;}
整個函式只有12行,如此的簡單卻高效
解題思路**於演算法導論習題4.1-5
注意:本文只討論最大子陣列的和的問題,所以後文提到最大子陣列時,都是指最大子陣列的和。
為了與習題裡面敘述保持一致,本節討論思路時下標都從1開始,a[1]表示第乙個元素。
已知 a[1..1] 的最大子陣列是第乙個元素,要麼 a[1..2] 的最大子陣列要麼是 a[1..1] 的最大子陣列,要麼是 a[i..2] 的最大子陣列。換個說法就是 a[1..2] 的最大子陣列要麼包含第二個元素,要麼不包含第二個元素;所以①需要從包含第二個元素和不包含第二個元素的兩種情況裡面選乙個最大的值出來。
不包含第二個元素的值是可以確定的,就是 a[1..1] 的最大子陣列,是已知的;為了方便起見,稱之為前最大子陣列。而包含第二個元素的最大子陣列需要另外去算;為了方便起見,我們稱之為邊界最大子陣列。我們真正需要的最大子陣列就是 前最大子陣列 和邊界最大子陣列中值較大的乙個。
那麼如何計算邊界最大子陣列?既然這種情況下已經確定了包含第二個元素,②那麼我們只需分兩種情況:只包含第二個元素,和不只包含第二個元素;同樣取這兩種情況的最大值。只包含第二個元素的情況是非常簡單的,邊界最大子陣列就只是a[2]的值;不只包含第二個元素的情況也簡單,不只包含第二個元素,那麼必定包含它的前乙個元素,即第乙個元素,所以我們需要它的前乙個元素的邊界最大子陣列。之後a[2]的邊界最大子陣列就是這兩種情況的最大值。
也就是說,要確定第a[1..2]的最大子陣列,唯一另外需要的元素就是第乙個元素的邊界最大子陣列。
現在情況清晰了,當計算a[1..2]的最大子陣列是,需要的值分別有:前最大子陣列(已知)、a[2]的值(已知)、前乙個元素的邊界最大子陣列。
如果看明白了思路,那麼**就很容易解釋了。
每一步都根據上一步的邊界最大子陣列和本次迭代的值求出本次的邊界最大子陣列,在把本次的邊界最大子陣列與前最大子陣列比較,確定本次的最大子陣列。
這裡因為與**結合著討論的,所以下標從0開始。
這裡再說一下兩個自定義名詞:
前最大子陣列:不包含當前元素的最大子陣列
邊界最大子陣列:只包含當前元素和不只包含當前元素,兩種情況的較大值
我們以陣列為例。
初始時兩個索引都為0,最大子陣列和邊界最大子陣列都是1;
當迭代索引為1時,本次值為-2,前一元素的邊界最大子陣列為1,所以邊界最大子陣列為-1,前最大子陣列為1,本次迭代的最大子陣列為前最大子陣列,值為1,不更新索引;
當迭代索引為2時,本次值為3,前邊界最大子陣列為-1,所以邊界最大子陣列為3;前最大子陣列為1,本次迭代的最大子陣列為邊界最大子陣列,值為3;此時需要把起始索引和終止索引都更新為當前索引,即2;
當迭代索引為3是,本次值為10,前邊界最大子陣列為3,所以邊界最大子陣列為13,前最大子陣列為*3,本次迭代的最大子陣列為邊界最大子陣列*,值為13;此時需要把終止索引更新為當前索引,卻不能更新起始索引;
…………
索引為2和索引為3的共同點在於,都是邊界最大子陣列大於前最大子陣列,都更新了終止索引;差別在於,索引2為時,邊界最大子陣列只包含了索引對應的值,所以可以更新起始索引;而索引3的邊界最大子陣列也包含了前一元素,所以只能更新終止索引。
此時可以把需要更新索引的情況概括如下:
條件①:本次的邊界最大子陣列只包含當前值,且大於前最大子陣列,則更新起始索引;
條件②:本次的邊界最大子陣列大於前最大子陣列,則更新終止索引;
更新終止索引的條件②應該是充分且必要的,然而更新起始索引的條件①是充分的,確並不是必要的。考慮一下陣列,當索引為2時,邊界最大子陣列為1,前最大子陣列為4,只滿足條件1的前半部分,然而整個陣列的最大子陣列的起始索引卻是2。所以條件①需要進行補充。
以下是第二個版本的兩個條件:
條件①:本次的邊界最大子陣列只包含當前值
條件②:本次的邊界最大子陣列大於前最大子陣列
當滿足條件①時,把當前索引記錄為快取索引,但並不更新起始索引;當滿足條件②時,更新終止索引為當前索引,更新起始索引為快取索引。
條件②的滿足總是要在條件①之後的。條件①可能標誌著乙個新的開始,因為條件①可以重複滿足,而條件②必定標誌著乙個結束。
思路理清以後,**就手到擒來了
int *maxsubarray( int* array, int length)
else
if( maxarray < boundry )
}int *result = new
int[3];
result[0] = maxbeginindex;
result[1] = maxendindex;
result[2] = maxarray;
return result;
}#include
using
namespace
std;
int main()
; int num = sizeof(a)/sizeof(a[0]);
int* result = maxsubarray(a, num);
cout
<<"begin:"
<0]<<" end:"
<1]<<" num:"
<2]num = sizeof(b)/sizeof(b[0]);
result = maxsubarray(b, num);
cout
<<"begin:"
<0]<<" end:"
<1]<<" num:"
<2]0;}
輸出結果為
begin:2 end:6 num:18主函式裡是有記憶體洩露,但這並不是重點begin:6 end:9 num:42
演算法 最大子陣列問題
問題描述 給定乙隻 在某段時間內的歷史 變化曲線,找出乙個能夠實現收益最大化的時間段。理解 為找出最大化的收益,需要考慮的是在買進和賣出時的 變化幅度,因此從該 的每日變化幅度來考慮問題比較合適。由此,可以將上述問題稍作變形 給定乙隻 在某段時間內的每日變化幅度,找出乙個合適的買進和賣出時間,以實現...
演算法 最大子陣列問題
今天我們要討論的是經典的問題 最大子陣列問題。題目如下 給定乙個陣列a 0,n 1 求a的連續子陣列,使得該陣列的和最大。例如 陣列 1,2,3,10,4,7,2,5 最大子陣列 3,10,4,7,2 這個問題已經算是比較經典的問題,這個問題有好幾種的求法,但是我們將去除暴力法,因為時間複雜度太高。...
最大子陣列和問題
演算法導論在分治策略一章中提到了最大子陣列和問題,我用c 實現了一下,還是挺簡單的,只不過要return最大子陣列的起始下標 結束下標和最大子陣列和這三個數有點麻煩,如要使用引用的話,因為要遞迴傳值所以不好實現,乙個可行的辦法是使用陣列,將這三個值放在陣列中傳遞。lz這裡並沒有寫這一過程。分治演算法...