求连续子序列和的最大值

问题:连续子序列最大和,其实就是求一个序列中连续的子序列中元素和最大的那个。 最大子序列和是指,给定一组序列,如 [1,-3,2,4,5],求子序列之和的最大值,对于该序列来讲,最大子序列之和为 2 + 4 + 5 = 11。java

解决方案有不少:一、两个for循环 2 动态规划 3分治算法 4 在线算法算法

一、 2个for循环的算法,思想是:以每个数为第一个数,在这些序列中找出最大值 举例的步骤以下:dom

二、动态规划 思想是:以每一个数为该子串的最后一个数,找出这个子串的最大值,而后在这些最大值中找最大值this

对上面的数进行举例.net

d[0]=1code

d[1]=max(d[0]-3,-3)=-2blog

d[2]=max(d[1]+2,2)=2递归

d[3]=max(d[2]+4,4)=6get

d[4]=max(d[3]+5,5)=11it

3 分治的作法 思想是:用二分查找的思路,先找出左子列的最大连续值,接着找出右子列的最大连续值,接着找出中间 的跨左右子列的最大值,而后取左子列、右子列、中间列值中的最大值。 举例说明:

以 4 - 3 -2 说明

lm 表明左字列最大值,rm表明右子列最大值,bm表明跨边界最大值

在线算法:思想是:循环里的j变量理解成序列的起点,可是这个起点有时会跳过若干数,当当前计算的序列a[i]到a[j]的和ThisSum一旦为负时,则ThisSum归 零,由于for循环的循环变量加1,则从a[j+1]开始加和,即起点跳到了负数和的子序列的下一个数字。

注:我将全部的全部的算法都作了部分修改,能适合所有为负数的状况 具体代码:

import java.util.Random;

public class MaxSub {

static int Upper=100000;

static int a[]=new int [Upper];

public static void main(String[] args) {

    for(int i=0;i<Upper;i++){
	
        Random random = new Random();
		
        a[i]=random.nextInt(100)-110;


    }

    long start = System.currentTimeMillis();
	//两个for循环的算法
    algorithm(a);
	
    long stop =System.currentTimeMillis();
	
    System.out.println((stop-start)+"ms");

    long start1 = System.currentTimeMillis();
	
	//动态规划算法
	
    alogrithm1(a);
	
    long stop1 =System.currentTimeMillis();
	
    System.out.println((stop1-start1)+"ms");
	

    long start2 = System.currentTimeMillis();
	
	//在线算法
	
    algorithm2(a);
	
    long stop2 =System.currentTimeMillis();
	
    System.out.println((stop2-start2)+"ms");
	

    long start3 = System.currentTimeMillis();
	//分治算法
    alogrithm3(a);
	
    long stop3 =System.currentTimeMillis();
    System.out.println((stop3-start3)+"ms");
}

public static void algorithm(int a[]){
    long Max=a[0];
    long temp;
    for(int i=0;i<a.length-1;i++){
         temp=a[i];
         //   这个地方很重要
        if(temp>Max)
            Max=temp;
        for(int j=i+1;j<a.length;j++)
        {
            temp = temp+a[j];
            if(temp>Max)
                Max=temp;
        }


    }
    if(a[a.length-1]>Max)
        Max=a[a.length-1];
    System.out.println(Max);


}

public static void alogrithm1(int a[]){

 long d[] = new long [a.length];
 d[0] = a[0];

 for(int i=1;i<a.length;i++){
     d[i]=Max(d[i-1]+a[i],a[i]);
  }
  long max=d[0];
  for(int i=1;i<d.length;i++){
      if(max<d[i])
          max=d[i];
  }

    System.out.println(max);


}

//找两个数中的最大值
public static long Max(long a,long b){
    return a>b?a:b;
}

public static void algorithm2(int a[]) {
    int temp=0;
    int maxSum, thisSum;
    maxSum = thisSum = 0;
    for (int i = 0; i < a.length; i++) {
        if(a[i]<0)
            temp++;
        thisSum += a[i];
        if (maxSum < thisSum)
            maxSum = thisSum;
        //当累加和为负数时,则从新赋值thisSum
        else if (thisSum < 0)
            thisSum = 0;

    }

    if(a.length==temp){
        int tempMax=a[0];
        for(int i=1;i<a.length;i++){
            if(tempMax<a[i])
                tempMax=a[i];
        }
        maxSum=tempMax;
    }

    System.out.println(maxSum);
}

public static void alogrithm3(int a[]){
    int max = submax(a,0,a.length-1);
    System.out.println(max);

}

public static int submax(int a[],int left,int right){
    //递归退出的条件
    if(left==right)
          return a[left];

    //取中心点
    int center =(left+right)/2;
    //取左边的连续和最大值
    int leftMax = submax(a,left,center);
    //取右边的连续和最大值
    int rightMax =submax(a,center+1,right);

    //为了去中间部分的最大值,先取左边跨边界的最大连续和
    int leftBorderMax=a[center],leftMaxTemp=a[center];
    for(int i=center-1;i>=left;i--){
        leftMaxTemp=leftMaxTemp+a[i];
        if(leftBorderMax<leftMaxTemp)
            leftBorderMax=leftMaxTemp;
    }

    //为了去中间部分的最大值,再取右边跨边界的最大连续和
    int rightBorderMax=a[center+1],rightMaxTemp=a[center+1];
    for(int i=center+2;i<=right;i++){
        rightMaxTemp=rightMaxTemp+a[i];
        if(rightBorderMax<rightMaxTemp)
            rightBorderMax=rightMaxTemp;
    }

    return Math.max(Math.max(leftMax,rightMax),leftBorderMax+rightBorderMax);

}

}

各个算法的相互比较:

从上表能够看出:在线算法时间最少,在线算法和动态算法差距不大,分治算法稍微比动态算法差一点

四种算法的时间复杂度为:o(n2),,o(n),o(nlogn),o(n),上图的实验结果基本符合算法复杂度的分析

参考文献:【1】http://www.javashuo.com/article/p-qlqjzfio-ge.html

【2】https://blog.csdn.net/jiaohanhan/article/details/71809357
相关文章
相关标签/搜索