问题:
- 给定一组数据,寻找该组数据中最大的子序列和,为简便计算,当子序列和为负数的时候,设定和为0。
- 例如给定数据为4 -3 5 -2 -1 2 6 -2,其最大子序列和为4 -3 5 -2 -1 2 6组成的11
问题分析:
- 首先考虑最简单的遍历方法,考虑到所有的子序列情况,但是考虑到时间复杂度达到O(n³),即使优化后也达到O(n²),遂放弃。
- 对于此类问题,考虑使用分而治之的方法,即对于该题目的分析为:一组数据的最大子序列和对应的子序列可能出现在原数据的左半侧,也可能出现在右半侧,还可能由左右两侧的各一部分组合而成(这两部分必须连接起来)。
算法设计:
- 采取分而治之的算法策略,首先将数据分为左右两部分,递归求出左右两部分的最大值。
- 为了控制左右两部分,可以通过向函数中传递数组以及左右下标来进行控制。
- 当递归到数据序列只有一个数据的时候,即左侧下标等于右侧下标的时候,返回该数据。对于最大子序列和出现在中间的情况来说,首先需要循环找到包含左侧最后一个数据的最大子序列和,之后找到右侧第一个数据的最大子序列和,之后将其相加。最后将三种情况进行比较,返回最大值即可。
- 注意对子序列和为负数的情况,进行和为0处理。
代码:
int MaxSubSum(int A[],int Left,int Right)
{
if(Left==Right)
{
if(A[Left]>0)
return A[Left];
else
return 0;
}
int MaxLeftSum,MaxRightSum;
int MaxLeftBorderSum,MaxRightBorderSum;
int LeftBorderSum,RightBorderSum;
int Center,i;
Center = (Left+Right)/2;
MaxLeftSum = MaxSubSum(A[],Left,Center);
MaxRightSum = MaxSubSum(A[],Center+1,Right);
MaxLeftBorderSum = 0;
LeftBorderSum = 0;
MaxRightBorderSum = 0;
RightBorderSum = 0;
for(i=Center;i>=Left;i--)
{
LeftBorderSum += A[i];
if(LeftBorderSum>MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
}
for(i=Center+1;i<=Right;i++)
{
RightBorderSum += A[i];
if(RightBorderSum>MaxRightBorderSum)
MaxRightBorderSum = RigthBorderSum;
}
return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum+MaxRightBorderSum);
时间复杂度
- O(N logN)==>暂时忘记咋证明了,等回头复习到那边的话补充吧