分治 最大子陣列

2021-09-29 10:06:36 字數 2405 閱讀 6666

問題描述:

給定乙個陣列,從中尋找最大子陣列(最大子陣列:子陣列內元素之和最大)。顯然此問題僅在陣列中包含正負值下才有效,否則,最大子陣列是其本身。

問題分析:

設原陣列為a[0……len-1],子陣列中任意元素為b[i]。則i-1,i-2,……0,i+1,i+2……len-1,皆有可能是子陣列內元素。因此我們可以將陣列劃分為乙個個單一元素,然後再通過合併確定子陣列的邊界情況。

問題求解:

暴力求解:

遍歷陣列的所有子集情況,最終找到的答案毋庸置疑,但是效能堪憂(n^2)。

分治求解:

先來分析下子陣列的位置情況。

首先將陣列一分為二(中間位置為mid),則子陣列位置不外乎以下三種情況:

毫無疑問,此性質在每次陣列二分之後(劃分為原陣列的一半)仍滿足。

左右兩側情況相較容易處理,但橫跨mid情況比較特殊(無法分解求解)。因此我們可以單獨處理此種情況。既然左右兩側均是子陣列的子集,則我們可以每次從mid開始向左和右遍歷。以向左為例:從mid開始遍歷,設此時最大子陣列為a[mid]。則最大子陣列要麼為a[mid],要麼為a[mid, mid-1,……mid-i](i=1, 2, ……,但i不能小於左側邊界)。向右遍歷與此情況相同,但避免mid被重複計算,則應從mid+1開始遍歷。

**示例:

#include

using

namespace std;

#define int -1e7

struct data

; data maxcrossingsubarray

(int

*a,int lo,

int mi,

int hi)

} sum =0;

for(

int i = mi+

1; i <= hi; i++)}

data temp;

temp.lo = left;

temp.hi = right;

temp.sum = leftsum + rightsum;

return temp;

}data maxsubarray

(int

*a,int lo,

int hi)

int mi =

(lo + hi)/2

; left =

maxsubarray

(a, lo, mi)

; right =

maxsubarray

(a, mi+

1, hi)

; cross =

maxcrossingsubarray

(a, lo, mi, hi);if

(left.sum >= right.sum && left.sum >= cross.sum)

return left;

else

if(right.sum >= left.sum && right.sum >= cross.sum)

return right;

else

return cross;

}int

main()

data temp =

maxsubarray

(a,0

, n-1)

; cout << temp.lo <<

" "<< temp.hi <<

" "<< temp.sum;

return0;

}

時間雜度分析:

maxsubarray()函式遞迴呼叫同二分演算法相同,最多經過logn此遞迴到達遞迴基,並且有n個元素需要合併,因此時間複雜度為o(nlogn)。

線性複雜度求解:

若a[0……i]最大子陣列為b,則a[0……i+1]的最大子陣列要麼為b要麼為a[0……i+1]內的任意一段。有了這個思路則可以自左至右遍歷整個陣列,每掃瞄乙個元素則按上述性質比較。

**示例:

#include

using

namespace std;

struct data

; data initdata

(data t,

int n)

data maxsubarray

(int

*a,int len)

}else

}return t;

}int

main()

; data temp =

maxsubarray

(n,8);

cout << temp.lo <<

" "<< temp.hi <<

" "<< temp.sum;

return0;

}

此種演算法只需要遍歷一遍整個陣列便可以求解問題,因此時間複雜度為o(n)。

分治演算法 最大子陣列

該演算法核心思想 任何連續最大子陣列必然處於以下三種情況 子陣列完全落在中點左邊 子陣列完全落在中點右邊 子陣列橫跨中點 所以先求出左邊最大的子陣列,再找出右邊的,然後從中間找。比較大小即可。中間點的最大子陣列容易確定,左右兩邊的無法確定,所以需要遞迴,把左右兩邊的陣列分解到只剩乙個元素時就能輕鬆確...

最大子陣列(分治法)

尋找a low,high 中的最大連續子陣列a i,j mid low high 2,欲求的最大連續子陣列出現的位置 1 出現在a low,mid 中 即 low i j mid 2 出現在a mid 1,high 中,即 mid 3 跨越了mid位置,出現在a low,high 中,即 low i...

最大子陣列的分治演算法

讀演算法導論當中的最大子陣列當中的分治演算法,涉及到的問題是怎麼從find max subarray 函式當中返回三個引數,所以用了vector來返回,總感覺不是太好,太浪費空間了,但也沒想到其他辦法。int max left,max right,sum int find max crossing ...