最大子序列问题及其求解----C 语言学习

18 篇文章 0 订阅

这两天看了看最大子序列问题,顺便的做一下笔记,最大子序列问题相信大家都再熟悉不过了,来回顾一下问题:

给定整数clip_image002[6](可能有负数),求clip_image002[8]的最大值(为方便起见,如果所有整数均为负数,则最大子序列和为 0 )。

下面来看三种实现方法:

1,使用两层 for 循环,算法复杂度显然是 O(N²):

?
intMaxSubSequenceSum(constintA[],intN)
{
    intThisSum,MaxSum,i,j;
    MaxSum = 0;
    for(i = 0; i < N; i ++)//外层的 for 循环
    {
        ThisSum = 0;
        for(j =i; j < N; j ++)//内层的 for 循环
        {
            ThisSum += A[j];
            if(ThisSum > MaxSum)
                MaxSum = ThisSum;
        }
    }
    returnMaxSum;
}

这种方法似乎是我们最先想到的解决办法,当然也很好理解。

2,使用“分治(divide-and-conquer)”的策略,其想法是把问题分成两个大致相等的子问题,然后递归的对它们进行求解,其算法复杂度是 O(N logN):

为了便于理解,再来解释一下这种方法:在我们的例子当中,最大子序列和可能出现在三处,或者整个出现在输入数据的左半部,或者整个出现在右半部,或者跨越输入数据的中部从而占据左右两半部分。前两种情况可以递归地进行求解,第三种情况的最大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到。然后将这两个和加在一起。作为一个例子,考虑如下的输入:

 

其中前半部分的最大子序列和为 6(A1 –> A3),后半部分的最大子序列和为 8 (A6 –> A7)。

前半部分包含最后一个元素的最大和为 4 (A1 –> A4),后半部分包含其第一个元素的最大和

?
-------------------------
 前半部分    |     后半部分
-------------------------
 4 -3 5 -2     -1 2 6 -2
-------------------------

为 7 (A5 –> A7)。因此,横跨这两部分且通过中间的最大和为 4 + 7 = 11 (A1 –> A7)。

于是,答案为 11。再来看看实现代码:

?
//主函数
staticintMaxSubSum(constintA[],intLeft,intRight)
{
    intMaxLeftSum, MaxRightSum;
    intMaxLeftBorderSum, MaxRightBorderSum;
    intLeftBorderSum, RightBorderSum;
    intCenter, i;
     
    if(Left == Right) /*基准情况*/
        if(A[Left] > 0)
            returnA[Left];
        else
            return0;
     
    /*处理递归*/
    Center = (Left + Right) / 2;
    MaxLeftSum = MaxSubSum(A, Left, Center);
    MaxRightSum = MaxSubSum(A, Center + 1, Right);
     
    MaxLeftBorderSum = 0;LeftBorderSum = 0;
    for(i = Center; i >= Left; i --)
    {
        LeftBorderSum += A[i];
        if(LeftBorderSum > MaxLeftBorderSum)
            MaxLeftBorderSum = LeftBorderSum;
    }
     
    MaxRightBorderSum = 0;RightBorderSum = 0;
    for(i = Center + 1; i <= Right; i ++)
    {
        RightBorderSum += A[i];
        if(RightBorderSum > MaxRightBorderSum)
            MaxRightBorderSum = RightBorderSum;
    }
    //处理完毕,找出和最大的一个子序列
    returnMax3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}
//调用函数
intMaxSubSequenceSum(constintA[],intN)
{
    returnMaxSubSum(A, 0, N - 1);
}
//比较函数
intMax3(intx,inty,intz)
{
    return(((x > y)?x:y) > z)?((x > y)?x:y):z;
}

3,使用一次 for 循环,算法复杂度为 O(N):

这个算法乍看上去不是很好理解,不过它的效率却是这三个当中最高的一个,仔细地琢磨的话会理解这个神奇的算法的:

?
intMaxSubSequenceSum(constintA[],intN)
{
    intThisSum, MaxSum, j;
    ThisSum = MaxSum = 0;
    for(j = 0; j < N; j ++)
    {
        ThisSum += A[j];
        if(ThisSum > MaxSum)
            MaxSum = ThisSum;
        elseif(ThisSum < 0)
            ThisSum = 0;
    }
    returnMaxSum;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值