【算法設計與分析】最大字段和(暴力,分治,動態規劃)

問題描述:

給定長度爲n的整數序列,a[1...n], 求[1,n]某個子區間[i , j]使得a[i]+…+a[j]和最大,或者求出最大的這個和。

例如(-2,11,-4,13,-5,2)的最大子段和爲20,所求子區間爲[2,4]。

1.窮舉法

枚舉左右區間然後遍歷該區間求解,時間複雜度O(n3)

public class Largestsubsection {

	public static int FindMax(int []a){
		int max = 0;
		for(int i = 0;i < a.length;++i){
			for(int j = 1;j < a.length;++j){
				int sum = 0;
				for(int k = i;k <= j;++k){
					sum += a[k];
				}
				if(sum >= max){
					max = sum;
				}
			}
		}
		return max;
	}
	
	public static void main(String[] args) {
		int []a = {-2,11,-4,13,-5,2};
		int max = FindMax(a);
		System.out.println(max);
	}
}

2.窮舉法+前綴和

在第一種方法的基礎上,預處理出前綴和,在枚舉左右區間之後,可以通過前綴和直接求解

例如求[l, r]區間的和,直接用sum[r] - sum[l - 1]求出。時間複雜度O(n2)(前綴和sum[i]表示前i位之和)

3.分治法

求解時分治,[1, n]的最大子段和只可能出現在[1, n / 2]或者[n / 2 + 1, n]或者起點位於[1, n / 2],後者位於[n / 2 + 1, n]。就可以直接分治最大子段和。時間複雜度O(nlog(n))。

public class Largestsubsection {

	public static int FindMax(int []a,int left,int right){
		if(left == right){
			return a[left]; //只有一個元素,直接返回
		}
		int center = (left + right)/2;
		// center爲0直接返回
		if(center == 0){
			return 0;
		}
		//遞歸求解左右區間的最大值
		int max = Math.max(FindMax(a, left, center), FindMax(a, center + 1, right));
		int j = 0,L = a[center-1],R = a[center];
		for(int i = center - 1;i >= left;--i){
			L = Math.max(L, j+=a[i]); // 左區域的最大字段和
		}
		j = 0; //清空之前的j
		for(int i = center;i <= right;++i){
			R = Math.max(R, j+=a[i]); // 右區域的最大字段和
		}
		return Math.max(max, L+R); //合併求解
	}

	public static void main(String[] args) {
		int []a = {-2,11,-4,13,-5,2};
		int left = 0,right = a.length-1;
		int max = FindMax(a, left, right);
		System.out.println(max);
	}
}

4.動態規劃法

子問題界定

設前邊界爲1,後邊界爲i,且C(i)是子序列A[1,..i]必須包含元素A[i]的向前連續延伸最大子段和


遞推方程滿足


遍歷所有以i (1≤i≤n)爲後邊界的最大子段和C(i)得出最優解OPT(A)=max1≤i≤n{Ci}

// 算法複雜度爲O(n)
public class Largestsubsection {
	
	public static int FindMax(int []a){
		int Sum = 0,Max = 0;
		for(int i = 0;i < a.length;++i){ // 子問題後邊界
			 Sum = (Sum + a[i]) > a[i] ? (Sum + a[i]):a[i];
			 if(Sum > Max){ // 更新最大和
				 Max = Sum;
			 }
		}
		return Max;
	}
	
	public static void main(String[] args) {
		int []a = {-2,11,-4,13,-5,2};
		int max = FindMax(a);
		System.out.println(max);
	}
}

動態規劃算法設計要點
(1) (劃分)多階段決策過程,每步處理一個子問題,界定子問題的邊界(初值問題)。
(2) 列出優化函數的遞推方程及初值。
(3) 問題要滿足優化原則或者最優子結構性質。即:一個最優決策序列的任何子序列本身一定是相對於子序列的初始和結束狀態的最優決策序列。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章