今天我們要討論的是經典的問題--最大子陣列問題。題目如下:給定乙個陣列a[0,....n-1],求a的連續子陣列,使得該陣列的和最大。例如:陣列:1,-2,3,10,-4,7,2,-5; 最大子陣列:3,10,-4,7,2;
這個問題已經算是比較經典的問題,這個問題有好幾種的求法,但是我們將去除暴力法,因為時間複雜度太高。接下來就是具體體現。
1、分治法。
分治法是演算法中常見的方法,它的主要思想就是分而治之。將問題最小化直到不能分為止,然後進行比較大小。具體的做法是將陣列從中間分開,那麼最大子陣列只有三種情況,要麼全部在左邊,要麼全部在右邊,要麼一點在左邊,一點在右邊。所以說,完全在左陣列、右陣列就用遞迴解決。跨在分界點上:實際上是左陣列的最大字尾和右陣列的最大字首和。因此,從分界點向前掃,向後掃就行了。現在我們就以題目中的陣列為例,我們先來看看**:
using接下來再來看看這個:system;
using
system.collections.generic;
using
system.linq;
using
system.text;
using
system.threading.tasks;
namespace
管窺演算法
static subarray maxaddsub(int a,int start,int
end)
int middle = (start + end) / 2
; subarray subarray1=maxaddsub(a, start, middle);
subarray subarray2 = maxaddsub(a, middle + 1
, end);
//第三種情況分在兩邊的
int sum1 =a[middle];
int startindex =middle;
int total = 0
;
for (int i = middle; i >= start; i--)
}int sum2 = a[middle + 1
];
int endindex = middle + 1
; total = 0
;
for (int i = middle+1; i <=end; i++)
}subarray subarray3;
subarray3.start =startindex;
subarray3.end =endindex;
subarray3.sum = sum1 +sum2;
if (subarray1.sum >= subarray2.sum && subarray1.sum >=subarray3.sum)
else
if (subarray2.sum >= subarray1.sum && subarray2.sum >=subarray3.sum)
else
}static
void main(string
args)
;subarray subarray = maxaddsub(a, 0, a.length - 1
); console.writeline(
"最大最大子陣列為:");
for (int i = subarray.start; i <= subarray.end; i++)
console.readkey();}}
}
在**中是有這句話的:
subarray subarray1=maxaddsub(a, start, middle);
subarray subarray2 = maxaddsub(a, middle + 1, end);
這兩段**的作用顯而易見的是用來只判斷左資料和右陣列組的,但是真實的其實不是這樣的,接下來我們就對遞迴進行分析。我們在執行第一次**的時候,左邊的為0 1 2 3(這個為索引。下面都是這個意思),右邊為4 5 6 7;然後subarray1會在一次的呼叫本身第二次左邊的為0 1,右邊為為2 3;接著的第三次還是一樣的 左邊為0 ,在這個時候**就到頭了,然後就會返回給上一級的subarray1,注意一下這個為第三次的subarray1,這個時候左陣列的使命正式完成了,終於可以進行第一次右邊陣列的遍歷了,在第一次右邊陣列因為只有乙個1所以沒有辦法進行遍歷,所以只能進行返回的操作了,這樣與第三次subarray1同層的subarray也出來了。在這個時候我們可以進行註明一下:先把第三次subarray1設為第三層,第三層 :subarray1為0 ,subaarray2為1;這兩個左右陣列賦值完了,就可以進行中間情況的判斷了,subarry3就是subarray1+subarray2的值,然後他們三個進行比較最大值並進行返回 。在這裡其實我們並不難看出01比較出來的之就是第二層左邊的值。同理右邊進行分類的時候可以相同情況。這樣的話,我們就可以知道了其實分治法中並沒有大中間的意思。我們在理解分治法的時候,一定要明白分支法就是讓問題進行分離,把它們進行分解一直分到不可分為止,然後讓兩個最小的變數進行比較大小,真正的中間情況其實是在不可再分下兩個相鄰值得相加。最後在說一句,在理解遞迴的時候,我們應該把落腳點放在不可再分的地方,這個才是遞迴的本質。
2、動態規劃法
在上面我們使用的分治法的方法,它的時間複雜度為ο(nlogn) ,相對於暴力法的時間複雜度n^2也是進步了不少;但是我們是否可以再跟進一步呢?答案當然是可以的,就是我們的動態規劃演算法,這個演算法將更加先進,因為它把時間複雜度下降到n,只需要需要乙個for迴圈就可以完成目標。接下來讓我們看看**如下:
static subarray maxsubdpmethod(int最後附上結果:args)
else
if(result
result=sum;
}subarray.sum =result;
return
subarray;
}
最後進行一下總結,當我們在解決問題的時候,優先放棄暴力法。
演算法 最大子陣列問題
問題描述 給定乙隻 在某段時間內的歷史 變化曲線,找出乙個能夠實現收益最大化的時間段。理解 為找出最大化的收益,需要考慮的是在買進和賣出時的 變化幅度,因此從該 的每日變化幅度來考慮問題比較合適。由此,可以將上述問題稍作變形 給定乙隻 在某段時間內的每日變化幅度,找出乙個合適的買進和賣出時間,以實現...
最大子陣列問題 演算法導論
分治法思想 分解 子陣列一定被原陣列左邊或者右邊包含,或者跨越原陣列mid下標。解決 前兩種完全包含的情況形成子問題遞迴求解,並且縮小了問題規模,後一種是我們要解決的問題。合併 剩餘的問題是求跨越mid的最大子陣列,並且從三種情況中選出和最大的。另外 算導中偽 返回的是三元組,這裡實現的話用結構體返...
最大子陣列問題
顧名思義,最大子陣列問題是求乙個陣列array中 和最大的非空連續子陣列 這樣的連續子陣列我們叫做最大子陣列,它的應用也有 很多,比如說找出時間序列中兩個時間節點使得這兩個時間節點對應的值的落差最大,如下圖 對於這類問題,通過求原始時間序列的一階差分得到序列array,此時求得array的最大子陣列...