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

来源:互联网 发布:乐视淘宝旗舰店 编辑:程序博客网 时间:2024/06/05 19:04
  • 问题描述

最大子序列问题是一个常见的数据结构问题,即求出给定数组{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
原创粉丝点击