问题描述:
给定n个整数(可能为负数)组成的序列a1,a2,a3,...,an, 求该序列子段和的最大值
例如:
X={-2, 11, -4, 13, -5, -2}, 其最大子段和为20
最大子段为:11,-4,13
解法一:穷举法
列举所有的可能,求其中的最大值
算法实现如下:
- /*
- * description: 最大子段和问题
- * 问题描述:给定n个整数(可能为负数)组成的序列a1,a2,a3,...,an,
- * 求该序列子段和的最大值
- * 解法一:穷举法,选取其中一个最大的值
- *
- * auther: cm
- * date: 2010/11/19
- */
- public class MaxSubSum
- {
- //穷举法
- public static int maxSubSum1(int[] a)
- {
- int maxSum = 0;
- for (int i = 0; i < a.length; i++)
- {
- for (int j = i; j < a.length; j++)
- {
- int sum = 0;
- for (int k = i; k <= j; k++)
- {
- sum += a[k];
- }
- if (sum > maxSum)
- {
- maxSum = sum;
- }
- }
- }
- return maxSum;
- }
- //穷举法改进,减少一层循环
- public static int maxSubSum2(int[] a)
- {
- int maxSum = 0;
- for (int i = 0; i < a.length; i++)
- {
- int sum = 0;
- for (int j = i; j < a.length; j++)
- {
- sum += a[j];
- if (maxSum < sum)
- {
- maxSum = sum;
- }
- }
- }
- return maxSum;
- }
- public static void main(String[] args)
- {
- int[] a = {-2, 11, -4, 13, -5, -2};
- //System.out.println(MaxSubSum.maxSubSum1(a));
- System.out.println(MaxSubSum.maxSubSum2(a));
- }
- }
最大子段和问题
解法二:分治法
算法分析:
最大子段和可能在三处出现。
1)整个出现在输入数据的左半部
2)整个出现在右半部。
3)跨越输入数据的中部从而位于左右两半部分之中
前两种情况可以递归求解,第三种情况的最大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)
以及后半部分的最大和(包含后半部分的第一个元素)而得到,前后两部分和相加。
三部分中的最大者,即为最大子段和.
例如:
前半部分 后半部分
4 -3 5 -2 -1 2 6 -2
其中前半部分的最大子段和为6(A1到A3),而后半部分的最大子段和为8(A6到A7);
前半部分包含其最后一个元素的最大和为4(A1到A4),后半部分包含其第一个元素的最大和为7(A5到A7),
则横跨这两部分的最大和为4+7=11;
故该序列的最大字段和为11
算法实现如下:
- /*
- * description: 最大子段和
- * 分治策略
- * 最大子段和可能在三处出现。
- * 1)整个出现在输入数据的左半部
- * 2)整个出现在右半部。
- * 3)跨越输入数据的中部从而位于左右两半部分之中
- * 前两种情况可以递归求解,第三种情况的最大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)
- * 以及后半部分的最大和(包含后半部分的第一个元素)而得到,前后两部分和相加。
- * 三部分中的最大者,即为最大子段和.
- * auther: cm
- * date: 2010/11/20
- */
- public class MaxSubSumRec
- {
- private static int maxSumRec(int[] a, int left, int right)
- {
- if (left == right)
- {
- if (a[left] > 0)
- {
- return a[left];
- }
- else
- {
- return 0;
- }
- }
- int center = (left + right) / 2;
- int maxLeftSum = maxSumRec(a, left, center);
- int maxRightSum = 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;
- }
- }
- return max(maxLeftSum, maxRightSum, maxRightBorderSum + maxLeftBorderSum);
- }
- //入口程序
- public static int maxSubSum(int[] a)
- {
- return maxSumRec(a, 0, a.length - 1);
- }
- //求三数中的最大值
- private static int max(int a, int b, int c)
- {
- int max = a > b ? a : b;
- max = c > max ? c : max;
- return max;
- }
- public static void main(String[] args)
- {
- int[] a = {-2, 11, -4, 13, -5, -2};
- System.out.println(MaxSubSumRec.maxSubSum(a));
- }
- }