设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