434
社区成员




给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。
要求算法的时间复杂度为O(n)。
通过分治的思想,可以不断把数组a[1:n]从中间平均分成两个部分:a[1:mid]和a[mid+1: n]两个部分,这样最大字段和出现的位置就会分成三种情况:
最大子段在左半端与右半端的通过不断递归相加求得,中间通过分别求两边再相加得出,最后再进行比较返回最大的子段和。
#include<iostream>
using namespace std;
int a[10000];
int MaxSum(int *a, int left, int right)
{
int sum = 0, MidSum = 0,LeftSum = 0, RightSum=0;
int center, s1, s2, lefts, rights;
if(left == right)
sum = a[left];
else{
center = (left + right)/2;
LeftSum = MaxSum(a, left, center);
RightSum = MaxSum(a, center+1, right);
s1 = 0;
lefts = 0;
for(int i = center;i >= left;i--)
{
lefts += a[i];
if(lefts > s1) s1 = lefts;
}
s2=0;
rights=0;
for(int j = center+1;j <= right;j++)
{
rights += a[j];
if(rights > s2)
s2 = rights;
}
MidSum = s1+s2;
if(MidSum < LeftSum)
sum = LeftSum;
else
sum = MidSum;
if(sum < RightSum)
sum = RightSum;
}
return sum;
}
int main(void)
{
int n,j;
cin>> n;
for(j = 0;j < n;j++)
cin>> a[j];
cout<< MaxSum(a,0,n-1);
return 0;
}
划分子问题:O(1)
求解子问题:2T(n/2)
合并子问题:O(n)
所以T(n) = 2T(n/2)+O(1)+O(n)
所以该算法的时间复杂度为T(n) = O(nlogn)
分治算法的核心思想可以归结为四个字:分而治之。分治法将规模为n的问题不断缩减,划分子问题,分成k个规模为n/m的我们比较容易能解决的子问题,这些子问题相互独立且与原问题性质相同,最后求出的小规模问题的解合并为更大规模的解,自底向上逐步合并求出原问题的解。