【算法设计与分析】最大字段和(暴力,分治,动态规划)

问题描述:

给定长度为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) 问题要满足优化原则或者最优子结构性质。即:一个最优决策序列的任何子序列本身一定是相对于子序列的初始和结束状态的最优决策序列。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值