求最大子序列问题-数据结构

  • 问题描述

最大子序列问题是一个常见的数据结构问题,即求出给定数组{1,3,4,5,6-10,3}
中加和最大的子序列,这个例子的解很明显是{1,3,4,5,6}。

  • 解决算法分析
    -这个问题一看便有一个明显的思路,即穷举法,利用双层循环来得到所有子序列的加和大小,然后取出最大的即为解。
    java代码:
public int findMax(int[] a){
        int max=0;
        for(int i=0;i<a.length;i++){
            int tempMax=0;
            for(int j=i;j<a.length;j++){
                tempMax+=a[j];
                if(tempMax>max){
                    max= tempMax;
                }
            }
        }
        return max;
    }

这个是最简单也是很多人想到的第一算法,他的时间复杂度明显是O(n2),
这里我主要想介绍的是另一种递归的解决方法,主要利用了分治算法的思想,先看代码:

    //分治算法
    public int findMax(int[] a,int left,int right){
        int result=0;
        //基准条件  既退出条件
        if(left==right){
            result=a[left]>0?a[left]:0;
            return result;
        }

        //重复调用
        int centerIndex=(left+right)/2;
        int maxLeft=findMax1(a, left, centerIndex);
        int maxRight=findMax1(a, centerIndex+1, right);

        //分治算法
        int maxBorderLeft=0,leftBorderSum=0;
        for(int i=centerIndex;i>=left;i--){
            leftBorderSum+=a[i];
            if(leftBorderSum>maxBorderLeft){
                maxBorderLeft=leftBorderSum;
            }
        }
        int maxBordeRight=0,rightBorderSum=0;
        for(int i=centerIndex+1;i<=right;i++){
            rightBorderSum+=a[i];
            if(rightBorderSum>maxBordeRight){
                maxBordeRight=rightBorderSum;
            }
        }

        //返回最大值
        result=maxBordeRight+maxBorderLeft;
        if(result<maxLeft){
            result=maxLeft;
        }
        if(result<maxRight){
            result=maxRight;
        }
        return result;
    }
    @Test
    public void test(){
        int[] x={1,2,3,4,-10,6};
        System.err.println(this.findMax1(x,0,x.length-1));
    }

这个代码可以按注释分为几块,递归算法第一步要设置算法的退出条件,也就是base case,这里的base case是这个数组只有一个元素的时候,那么直接退出就可以了,如果不是的话要用分治思想来求解:
1,把数组分成两个部分,分别求出最大的和, 然后从中间向两遍查找,求出最大的和,三个部分最大的数即为本问题的解。这里读者最好画图来帮助理解,这个是这个算法的关键。 时间复杂度是O(nlogn)

最后介绍一种这个问题的最优解,

public int findMax(int[] a){
        int result=0,sum=0;
        for(int i=0;i<a.length;i++){
            sum+=a[i];
            if(sum>result){
                result = sum ;
            }else if(sum<0){
                sum=0;
            }
        }
        return result;
    }

这个的时间复杂度降到了O(n), 优秀的算法总是很难懂,但是我们可以拿上面的例子一一带入来看看为什么这个算法成立,才能理解这种写法
例子{1,2,4-10,4}

第一次执行:result=1, sum 1
第二次执行:result=3, sum 3
第三次执行:result=7, sum 7
第四次执行:result=7, sum 0
第五次执行:result=7, sum 4

结果是7

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专注网赚的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值