434
社区成员
发帖
与我相关
我的任务
分享用分治法求最大字段和的三种计算情况:
首先在数组 mid = (right - left) / 2 出将数组分开
伪代码如下:
//伪代码
Function<MaxSum> (int* a, int left , int right){
//传值:数组a,左右边界
if right-left=1 then
return
end if
// 划分[left,mid)和[mid,right)分治
mid←x+(y-x)/2
L←maxsum(a,left,mid)
R←maxsum(a,mid+1,right)
if L>R then
max←L
else
max←R
end if
// 求出处于中间的连续子序列最大和
// 先求从中间向左最大值
tempSum←0
leftSum←a[m-1]
for i←m-1 downto right do
tempSum←tempSum+a[i]
if leftSum<tempSum then
leftSum←tempSum
end if
end for
// 再求从中间向右最大值
tempSum←0
rightSum←a[m]
for i←m to left do
tempSum←tempSum+a[i]
if rightSum<tempSum then
rightSum←tempSum
end if
end for
midSum←leftSum+rightSum
if max<midSum then
max←midSum
end if
return max
end Function
}
程序代码:
int MaxSum(int *a, int left, int right)
{
if(right==left)
return a[left]>0?a[left]:0;
int mid = (left+right)/2;
//左边区间的最大子段和
int leftMax = MaxSum (a,left,mid);
//右边区间的最大子段和
int rightMax = MaxSum(a,mid+1,right);
//以下求端点分别位于不同部分的最大子段和
//center开始向左移动
int sum = 0;
int left_max = 0;
for(int i = mid; i >= left; --i)
{
sum += a[i];
if(sum > left_max)
left_max = sum;
}
//center+1开始向右移动
sum = 0;
int right_max = 0;
for(int i = mid+1; i <= right; ++i)
{
sum += a[i];
if(sum > right_max)
right_max = sum;
}
int res = left_max+right_max;
if(res < leftMaxInterval)
res = leftMaxInterval;
if(res < rightMaxInterval)
res = rightMaxInterval;
return res;
}
分治法时间复杂度主要是将问题一分为二,分解成规模n/2的子问题,最后再合并子问题
T(c) = O(1)
T(n) = 2T(n/2) + O(n)
即 根据主定理有 T(n) = O(nlogn)
分治法可以将一个难以直接解决的大问题,划分成一些规模较小的子问题,以便各个击破,分而治之,如此分解下去,直到问题规模足够小,很容易求出其解为止,再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解。代码结构也会十分清晰,比较简洁明了。