434
社区成员
发帖
与我相关
我的任务
分享将序列a[1:n]分成长度相等的两段a[1:n/2]和a[n/2+1:n],分别求出这两段的最大字段和,则a[1:n]的最大子段和有三中情形:
1.a[1:n]的最大子段和与a[1:n/2]的最大子段和相同;
2.a[1:n]的最大子段和与a[n/2+1:n]的最大子段和相同;
3.a[1:n]的最大字段和为中间段;
可用递归方法求得情形1、2。对于情形3,可以看出a[n/2]与a[n/2+1]在最优子序列中。
因此可以在a[1:n/2]中计算出s1;
在a[n/2+1:n]中计算出s2;
则s1+s2即为出现情形3时的最优值。
伪代码如下:
int maxSubSum(int a[], int left, int right){
int sum = 0;
if(left == right){
sum = a[left] > 0 ? a[left] : 0;
}
else{
int center = (left + right) / 2;
int leftSum = maxSubSum(a, left, center);
int rightSum = maxSubSum(a, center + 1, right);
int s1 = 0;
int lefts = 0;
for(int i = center; i >= left; i--){
lefts += a[i];
if(lefts > s1) s1 = lefts;
}
int s2 = 0;
int rights = 0;
for(int i = center + 1; i < right; i++){
rights += a[i];
if(rights > s2) s2 = rights;
}
sum = s1 + s2;
if(sum < leftSum) sum = leftSum;
if(sum < rightSum) sum = rightSum;
}
return sum;
}
每次将原问题分解成左右两个子问题,最后合并n个子问题的答案,由此可得
分解子问题:O(1);求解子问题:2 T(n/2) (把问题分成左右两边数量减半即T(n/2),左右两边相加:T(n/2)*2)
合并子问题:O(n)
该算法的时间复杂度为T(n) = 2 T(n/2) + O(n),故T(n) = (nlogn)
分治法的基本思想就是把一个规模为n的问题分解成k个规模较小的子问题,这些子问题互相独立且与原问题相同。
(1) 将求解的较大规模的问题分割成k个更小规模的子问题。
(2) 对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。
(3) 将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解。
这种思想其实应用很广泛,只是生活中不去特别注意。将一个复杂的且规模庞大的问题通过不断细分不断细分,变成一个个易于理解易于解决的子问题,逐一击破后合并成为最后的解