寻找最大子序列和

问题:

  • 给定一组数据,寻找该组数据中最大的子序列和,为简便计算,当子序列和为负数的时候,设定和为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)==>暂时忘记咋证明了,等回头复习到那边的话补充吧

猜你喜欢

转载自www.cnblogs.com/cyh-blackhouse/p/12420955.html
今日推荐