最大子序列和问题

问题
给定(可能有负的)整数 A1,A2,A3,...,AN , 求 jk=iAk 的最大值。

解1
最先得到的方法大概是使用两层循环,遍历所有的子序列,求和后比较,记录最大者,以及最大者的起点,终点。时间复杂度 O(N2) , 代码如下:

    public int getMaxSumOfSubSeqSlow(int[] inputArr)
    {
        int max = 0;
        int startPoint = 0;
        int endPoint = 0;
        for(int i=0; i<inputArr.length; i++)
        {
            int sum = 0;
            for(int j=i; j<inputArr.length; j++)
            {
                sum += inputArr[j];
                if(sum > max)
                {
                    max = sum;
                    startPoint = i;
                    endPoint = j;
                }
            }
        }
        return max;
    }

解2
对任意成为最终解的子序列,都不会有和为负数的前缀。因为若有和为负数的前缀,去掉该前缀的剩余子序列会大于原有子序列,原有子序列即不是最终解,不满足假设的前提。
于是,可以从0开始累加,当累加的和大于现有最大值时,更新最大值。当累加的和小于0时,从下一位开始重新累加。从下一位开始累加不会错过最优解,因前面的每一次被抛弃的子序列,和均为负数,整体的和也是负数。这是 O(n) 的解法。
这种解法只对数据进行一次扫描,不需要存储扫描过的数据,算法可在任意时刻对已读入的数据给出一个最优解。具有这种特性的算法叫做联机算法(on-line algorithm)。仅需要常量空间,并以线性时间运行,几乎是完美的算法。

    public int getMaxSumOfSubSeq(int[] inputArr)
    {
        int max = 0;
        int sum = 0;
        int startPoint = 0;
        int endPoint = 0;
        int tmpStartPoint = 0;
        for(int i=0; i<inputArr.length; i++)
        {
            sum += inputArr[i];
            if(sum < 0)
            {
                tmpStartPoint = i+1;
                sum = 0;
            }
            else if(sum > max)
            {
                startPoint = tmpStartPoint;
                endPoint = i;
                max = sum;
            }
        }
        return max;
    }

该问题有优于解1 的分治解法,时间复杂度为 O(N logN) 。整体思路是:将序列分为大小大致相等的两个子序列,最优解或者在左半边,或者在右半边,或者横跨两者。根据分割点分别向左/右求得最大和,相加即为横跨情况的最大解,该横跨情况的最优解与递归得到的左边最大解,右边最大解比较,即为整个序列的最大解。未编写代码。

若想在有多个最优解时获取所有的解,可将startPoint等改用列表存储。
随机生成100000个数时,对比如下:
这里写图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值