最大子段和

设A=<a1,a2,...,an>是n个整数的序列,称<ai,...,aj>为该序列的子序列,其中1<=i<=j<=n.子序列的元素之和称为A的子段和.

例如,A=<-2,11,4,13,-5,-2>,那么它的子段和是:

长度为1的子段和:-2,11,-4,13,-5,-2

长度为2的子段和:9,7,9,8,-7

长度为3的子段和:5,20,4,6

长度为4的子段和:18,15,2

长度为5的子段和:13,13

长度为6的子段和:11

其中最大的子段和是 11-4+13=20


1.蛮干法:

枚举A的所有连续子序列并且求和,通过比较找出最大子序列.

算法复杂度:O(n^3)


2.分治算法:

在[n/2]将A分为A1和A2前后两部分,

若分割点为k,即A[i...k],A[k+1...j]

取得连续最大值的情况有三种:

第一种情况:sum1 = A[i...k] 左部分的连续最大值

第二种情况:sum2 = A[k+1...j] 右部分的连续最大值

第三种情况:

该最大连续子序列一部分在左边,一部分在右边,这时

left = A[k]+A[k-1]+...+A[m] 从分割点向左最大连续子段和

right = A[k+1]+A[k+2]+...+A[n] 从分割点向右最大连续子段和

1<=m,n<=j

sum3 = left+right

取 max{sum1,sum2,sum3}

递推方程:

T(n) = 2T(n/2)+O(n), T(1) = 0

根据主定理算法复杂度:

O(nlogn)


动态规划算法:

设C[i]为A[1...i]中必须包含元素A[i] 的最大子段和.

这样,C[i]表示的是A的每一位并且必须加上这一位后的最大子段和.


递推关系:

C[i] = max{C[i-1]+A[i],A[i]}

从递推式可以看出,当C[i-1]为负数时,直接取A[i]的值为C[i],这也是好理解的,

一定要清楚C[i]是包含当前A[i]的最大连续子序列的和

算法复杂度:

O(n)

算法:

package com.动态规划;


/// <summary>
/// 求解最大子段和,返回结果以及最优解的始末下标
/// </summary>
/// <param name="seq">输入序列</param>
/// <param name="beginIndex">返回最优解的起始下标</param>
 /// <param name="endIndex">返回最优解的结束下标</param>
/// <returns>最大子段和</returns>
public class MaxSubSum {
	public static int MaxSubSum(int seq[]){
		if(seq == null || seq.length == 0){
			return -1;
		}
		int beginIndex =0,endIndex = 0;
		int curSum = seq[0] ;
		int bestResult = seq[0];
		int curBeginIndex = 0;
		for(int i=1; i<seq.length;i++){
			//有正数那么和最小都为最小的正数
			//bestResult已经记录i前的最大的子串的和以及坐标,当cursum<0时,i前的最大子串的结束到
			//当前点的数据只会减少cursum的值
			if(curSum > 0){
				curSum += seq[i];
			}else{
				curSum = seq[i];
				curBeginIndex = i;
			}
			//每对一个数进行处理后都要比较更新最大值
			if(curSum > bestResult){
				bestResult = curSum;
				beginIndex = curBeginIndex;
				endIndex = i;
			}
		}
		System.out.println("开始的下标:"+beginIndex+" 结束的下标:"+endIndex);
		return bestResult;
	}
	
	public static void main(String[] args) {
		int seq[] = {20,-11,10,-1,-4,-5,-10,-2,-1,-2,-1,-9,11};
		//int seq[] = {-20,-11,-10,-1,-4,-5,-10,-2,-3,-2,-3,-9,-11};
		for(int i:seq){
			System.out.print(i+" ");
		}
		System.out.println();
		int result = MaxSubSum(seq);
		System.out.println("最大子序列的和为:"+result);
	}
}

结果:

20 -11 10 -1 -4 -5 -10 -2 -1 -2 -1 -9 11 
开始的下标:0 结束的下标:0
最大子序列的和为:20


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值