求連續子序列和的最大值

問題:連續子序列最大和,其實就是求一個序列中連續的子序列中元素和最大的那個。 最大子序列和是指,給定一組序列,如 [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
相關文章
相關標籤/搜索