最大连续子序列和(Java语言版)
题目描述
给定整数A 1 , A 2 , A 3 , . . . , A n A_1,A_2,A_3,...,A_nA1,A2,A3,...,An(可能是负整数),求∑ k = i j A k \sum_{k=i}^{j}A_k∑k=ijAk的最大值。如果所有的整数均为负数,那么最大子序列的和为0。
简单O ( N 3 ) O(N^3)O(N3)算法
最简单的算法就是直接穷举搜索,或称蛮力算法。
public static int maxSubsequenceSum(int[] a) {
int maxSum = 0;
for (int i = 0; i < a.length; i++) {
for (int j = i; j < a.length; j++) {
int thisSum = 0;
for (int k = i; k <= j; k++)
thisSum += a[k];
if (thisSum > maxSum)
maxSum = thisSum;
}
}
return maxSum;
}
改进的O ( N 2 ) O(N^2)O(N2)算法
我们试图从算法中删除嵌套循环,这样会降低运行时间。改进算法使用∑ k = i j A k = A j + ∑ k = i j − 1 A k \sum_{k=i}^j A_k=A_j+\sum_{k=i}^{j-1} A_k∑k=ijAk=Aj+∑k=ij−1Ak。换句话说就是我们已经计算了子序列i , . . . , j − 1 i,...,j-1i,...,j−1的和,那么计算子序列i , . . . , j i,...,ji,...,j应该不会花太多时间,我们只需要多家一次计算即可。改进后的算法如下,只使用了两层嵌套循环。运行时间为O ( N 2 ) O(N^2)O(N2)。
public static int maxSubsequenceSum(int[] a) {
int maxSum = 0;
for (int i = 0; i < a.length; i++) {
int thisSum = 0;
for (int j = i; j < a.length; j++) {
thisSum += a[j];
if (thisSum > maxSum)
maxSum = thisSum;
}
}
return maxSum;
}
线性算法
我们可以从分析中排除大量可能的子序列。很显然,最大子序列不可能从负数开始,因此,如果a [ i ] a[i]a[i]为负,那我们可以跳过内循环,并增加i ii。更普遍的,最大子序列不可能以负子序列开始。
public static int maxSubsequenceSum(int[] a) {
int maxSum = 0;
int thisSum = 0;
for (int i = 0, j = 0; j < a.length; j++) {
thisSum += a[j];
if (thisSum > maxSum)
maxSum = thisSum;
else if (thisSum < 0) {
i = j + 1;
thisSum = 0;
}
}
return maxSum;
}
如果我们检测到和为负数,可以将i ii直接变成j jj。
版权声明:本文为yu007527原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。