问题描述:最大子序列
给定一整数序列A1, A2,... An (可能有负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大。
例如: 整数序列-2, 11, -4, 13, -5, 2, -5, -3, 12, -9的最大子序列的和为21,子序列起始下标为1,结束下标为8。
复杂度:O(n)
// return 子序列最大和,start 为子序列的开始下标,end为子序列的结束下标
public int maxSub(int a[]) {
int max = 0;
int tempSum = 0;
int size = a.length;//数组长度
int start = 0;//起始下标
int end = 0;//结束下标
boolean firstFlag = false;
for (int i = 0; i < size; i++) {
tempSum += a[i];
if (tempSum > max) {
max = tempSum;
end = i;
if (firstFlag == false) {
start = i;
}
firstFlag = true;
} else if (tempSum < 0) {
tempSum = 0;
firstFlag = false;
if (a[i] > 0) {
start = i;
}
}
}
System.out.println("size=" + size + " start =" + start + " end="
+ end + " sub length=" + (end - start + 1));
return max;
}
备注:
经测试了十几组数据,子序列起始下标正确,但不排除特殊情况。
可如此解决:用maxSum(子序列和)从end下标向前减a[ end--],直至=0,可得出起始下标。
原理:(摘自网络)
1 当Sum(i, j)<0时,Sum(i, j),Sum(i, j+1),Sum(i, j+2)...Sum(i, n)都不可能是最大值。
2 由1可知,最优子序列不可能以负数开头。3 若Sum(i, j),Sum(i, j+1),Sum(i, j+2)...Sum(i, n)都不为负数,则以A[i+1]...A[n]开头的子序列和都不可能最大。
因而,算法变为:从左到右的一次扫描,不断累加,并更新最大值,当累加A[j]时值为负,则累加值清零,开始从 A[j+1] 累加。