求最大子序列和

一、问题

给定整数A1,A2,A3……An,求∑ Ak的最大值。(出自《数据结构与算法分析》第二章)

二、解决

/*
     * 方法一
     */
    public static int maxSubSum1(int []a){
        int maxSum=0;
        for(int i=0;i<a.length;i++){
            for(int j=0;j<a.length;j++){
                int thisSum=0;
                for(int k=i;k<=j;k++){
                    thisSum+=a[k];//O(N3)
                }
                if(thisSum>maxSum){
                    maxSum=thisSum;
                }
            }
        }
        return maxSum;
    }
/*
     * 方法二
     */
    public static int maxSubSum2(int []a){
        int maxSum=0;
        for(int i=0;i<a.length;i++){
            int thisSum=0;
            for(int j=i;j<a.length;j++){
                thisSum+=a[j];//O(N2)
                if(thisSum>maxSum){
                    maxSum=thisSum;
                }
            }
        }
        return maxSum;
    }
/*
     * 方法三---分治策略
     * 最大序列和由三部分组成
     * 左半部,右半部,跨越输入数据的中部而位于左右两半部分之中
     */
    public static int maxSubSum3(int []a){
        return maxSumRec(a, 0, a.length-1);
    }

    public static int maxSumRec(int []a,int left,int right){
        if(left==right){//基准情况
            if(a[left]>0){
                return a[left];
            }else{
                return 0;
            }
        }
        int center=(left+right)/2;
        int maxLeftSum=maxSumRec(a, left, center);
        int maxRightSum=maxSumRec(a, center+1, right);

        int maxLeftBorderSum=0,leftBorderSum=0;
        for(int i=center;i>=left;i--){//求出包含前半部分最后一个元素的最大值
            leftBorderSum+=a[i];
            if(leftBorderSum>maxLeftBorderSum){
                maxLeftBorderSum=leftBorderSum;
            }
        }

        int maxRightBorderSum=0,rightBorderSum=0;
        for(int i=center+1;i<=right;i++){//求出包含后半部分最后一个元素的最大值
            rightBorderSum+=a[i];
            if(rightBorderSum>maxRightBorderSum){
                maxRightBorderSum=rightBorderSum;
            }
        }

        return max3(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightBorderSum);

    }
    public static int max3(int a,int b,int c){
        int max;
        if(a>b){
            max=a;
        }else {
            max=b;
        }
        if(c>max){
            max=c;
        }
        return max;
    }
/*
     * 方法四
     * 任何负的子序列不可能是最大子序列的前缀
     */
    public static int maxSubSum4(int []a){
        int maxSum=0,thisSum=0;
        for(int j=0;j<a.length;j++){
            thisSum+=a[j];
            if(thisSum>maxSum){
                maxSum=thisSum;
            }else if(thisSum<0){
                thisSum=0;
            }
        }
        return maxSum;
    }

三、分析

1、方法一用了三层for循环,有变量i是为了确定子序列的开始位置,j则为子序列的结束位置,k变量则是从i到j以便求得子序列的值。因为是三层for循环,每个循环的最大次数均为n,所以运行时间最坏为O(n^3)。
2、方法二则是在方法一之上的改进,去掉了变量k,可以看做用变量j包含变量k的原有作用,因为是两层for循环,运行时间最坏为O(n^2)。
3、方法三用了分治策略(所谓分治就是把问题分成两个大致相等的子问题,然后递归地分别解决,最后将两个问题的解凑到一起并可能做些少量操作,最终得到总问题的解),这里把最大子序列可能出现的位置分为三个位置,即数列的左半部分,右半部分,跨越输入数据的中部而位于左右两半部分之中,运行时间为O(nlogn)。
4、方法四建立在任何负的子序列不可能是最大子序列的前缀这一原理上而写。在四个方法中,它的效率是最高的。

Do what you say,say what you do

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值