問題描述:
給定乙個陣列,從中尋找最大子陣列(最大子陣列:子陣列內元素之和最大)。顯然此問題僅在陣列中包含正負值下才有效,否則,最大子陣列是其本身。
問題分析:
設原陣列為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 ...