利用分治策略來解決最大子陣列問題

2021-08-08 18:23:22 字數 2282 閱讀 3021

求解乙個陣列的最大子陣列,例如給定陣列b[0,,,,,,n-1],就是找到滿足條件的一組i和j使得當i <= j時,有b[j] - b[i]的值達到最大。這裡我們很容易想到一種暴力求解的方法。從n個下標中任意選取兩個,就是n*(n-1)/2中組合,來計算得到最大子陣列即可。此時這種演算法的時間複雜度為o(n^2),但是若我們採用如下分治策略來進行優化的話,我們可以得到乙個演算法時間複雜度為o(nlogn)的演算法。

分治策略:首先我們來對問題進行一下轉換,把求b的最大子陣列的問題轉換成求a的最大子陣列問題,陣列a即反應b中數的變化的乙個陣列,其中乙個元素a[i](i >=1)代表的是b[i]-b[i-1],這樣的話,我們看問題的角度就發生了一定的變化,即不在關心b中的每個數

是多少,而是關心b中每個數相對於前乙個數是如何變化的,即問題現在轉化成了尋找a的和最大的非空連續子陣列。

在明確了問題轉化成為求解a的和最大的非空連續子陣列後,我們來思考如何用分治技術來求解最大子陣列問題。假定我們尋找子陣列a[low.......high]的最大子陣列。使用分治技術意味著我們要將子陣列劃分為兩個規模盡量相等的子陣列。也就是說,找到子陣列的**位置,比如mid,然後考慮求解兩個子陣列a[low....mid]和a[mid+1...high]。經分析可知,a的任何連續子陣列a[i....j]所處的位置必然是以下三種情況之一:

完全位於子陣列a[low....mid]中,因此low <= i <= j <= mid

完全位於子陣列a[mid+1....high]中,因此mid+1 <= i <= j <= high

跨越了中點,因此low <= i  <= j <= high

因此a[low...high]的乙個最大子陣列所處的位置必然是三種情況之一。實際上a[low....high]的乙個最大子陣列必然是完全位於a[low...mid]中,完全位於a[mid+1,high]中,或者跨越終點的所有子陣列的最大者。我們可以遞迴地求解a[low...mid]和a[mid+1...high]的最大子陣列,因為這兩個子陣列問題仍然是最大子陣列問題,只是規模更小。因此剩下的工作就是尋找跨越重點的最大子陣列,然後在三者情況中選取和最大者。

]的最大子陣列,然後將其合併即可。

在有了以上方法後,我們很容易來列出求解這個問題的最終演算法:

若low == high 返回low,high,a[low]或者a[high]

計算mid = (low+high)/2

計算a(low,mid)的最大子陣列

計算a(mid+1,high)的最大子陣列

計算橫跨中點的a(low,mid,high)的最大子陣列

選取乙個最大的即可

在有了這個演算法後,**編寫就比較容易了,一種c++的實現如下

#include#includeusing namespace std;

//定義子陣列結構體,分別代表子陣列的下界和上界,以及和

struct sub_array ;

//尋找跨越中點的最大子陣列的函式

sub_array find_max_crossing_subarray(int *a, int low, int mid, int high)

} sum = 0;

//計算中點右側的最大子陣列

for (int j = mid + 1; j <= high; j++)

} //將二者進行合併

cross_array.max_sum = left_sum + right_sum;

return cross_array;

}//尋找最大子陣列的函式

sub_array find_maximun_subarray(int *a, int low, int high)

else

else if (right_array.max_sum >= left_array.max_sum && right_array.max_sum >= cross_array.max_sum)

else }}

int main()

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

sub_array solution;

solution = find_maximun_subarray(a, 1, num-1);

cout << solution.max_left<<" "<< solution.max_right<<" "<演算法分析:可以看出當n = 1時,演算法的時間複雜度為o(1),當n >= 2是,t(n) = 2t(n/2) + o(n),故綜上所述,演算法的時間複雜度為o(nlogn),可以看出比起暴力求解的o(n^2)的時間複雜度,已經明顯優化了不少。

分治策略之最大子陣列

分治策略是將父問題差分成的多個子問題,然後遞迴的方式解決子問題。整個思想和動態規劃類似,不過分治策略不要求最優解問題,而只是把父問題分解成子問題。步驟 分解 divide 先將問題劃分成子問題。子問題的形式與原問題相同。解決 conquer 遞迴解決問題,當問題縮小到一定程度就能夠直接求解。合併 c...

分治策略 求最大子陣列

只有當陣列中包含負數時,最大子陣列問題才有意義。如果所有元素都是非負的,最大子陣列問題沒有任何意義,因為整個陣列和肯定是最大的 1 public class findmaxsubarraydemo 4int result arr findmaximumsubarray arr,0,arr.lengt...

分治策略之最大子陣列問題

問題 乙個整數陣列中的元素有正有負,在該陣列中找出乙個連續子陣列,要求該連續子陣列中各元素的和最大,這個連續子陣列便被稱作最大連續子陣列。比如陣列的最大連續子陣列為,最大連續子陣列的和為5 2 1 2 8。一 暴力解法 include using namespace std class soluti...