给定(有可能是负的)整数,求的最大值。如果所有整数均为负数,则最大子序列和为0。
第一种算法如下,只是穷举式的尝试所有可能。很明显,该算法一定会正确的运行,但运行时间为。
/** * 最直观简单的实现方式,时间复杂度O(N^3)…… * @author liufl / 2014年8月5日 */ public class SumImplSimple implements Sum { @Override public int maxSubSum(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)…… * @author liufl / 2014年8月5日 */ public class SumImplFasterCompare implements Sum { @Override public int maxSubSum(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; } }
/** * 递归实现。也被称为分治法。时间复杂度O(NlogN) * @author liufl / 2014年8月5日 */ public class SumImplRecursive implements Sum { @Override public int maxSubSum(int[] a) { return this.maxSumRec(a, 0, a.length - 1); } /** * 递归求子序列的最大子序列和 * @param a 原序列 * @param left 子序列的左边界 * @param right 子序列的右边界 * @return */ private int maxSumRec(int[] a, int left, int right) { if (left == right) { // 子序列是一个单值。基本情形 if (a[left] > 0) { return a[left]; // 是正数,返回 } else { return 0; // 不是正数,返回0 } } // 中间分成两个子序列,求各子序列的最大子序列和。递归 int center = (left + right) / 2; int maxLeftSum = this.maxSumRec(a, left, center); int maxRightSum = this.maxSumRec(a, center + 1, right); // 从中部向左加和的最大和 int maxLeftBorderSum = 0; int leftBorderSum = 0; for (int i = center; i >= left; i--) { leftBorderSum += a[i]; if (leftBorderSum > maxLeftBorderSum) { maxLeftBorderSum = leftBorderSum; } } // 从中部向右加和的最大和 int maxRightBorderSum = 0; int rightBorderSum = 0; for (int i = center + 1; i <= right; i++) { rightBorderSum += a[i]; if (rightBorderSum > maxRightBorderSum) { maxRightBorderSum = rightBorderSum; } } // maxLeftBorderSum + maxRightBorderSum 中部最大子序列和 // 取左、右、中部最大子序列和中最大值 return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum); } /** * 取三值中最大值 * @param int1 * @param int2 * @param int3 * @return */ private int max3(int int1, int int2, int int3) { return Math.max(Math.max(int1, int2), int3); } }
/** * 最佳的方案。正常思维想不到,代码却很好理解。时间复杂度O(N) * 但在输入数全为负数时,输出结果是0,而不是负数。 * @author liufl / 2014年8月5日 */ public class SumImplBest implements Sum { @Override public int maxSubSum(int[] a) { int maxSum = 0; // 已知最大和 int thisSum = 0; // 当前有效和 for (int j = 0; j < a.length; j++) { // 遍历求和 thisSum += a[j]; if (thisSum > maxSum) // 比较当前和与已知最大和 maxSum = thisSum; else if (thisSum < 0) // 当前和是负的,会拖累后面的和 thisSum = 0; // 清零,从下一位重新加和 } return maxSum; } }