【试题描述】输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。
求所有子数组的和的最大值。要求时间复杂度O(n)。
思路:当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。
【参考代码】
1 public static int maxSum(int[] a) { 2 int sum = 0; 3 int b = 0; 4 for (int i = 0; i < a.length; i++) { 5 if (b < 0) 6 b = a[i]; 7 else 8 b += a[i]; 9 if (sum < b) 10 sum = b; 11 } 12 return sum; 13 }
思路2:动态规划实现
/*
*问题:输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。
*求所有子数组的和的最大值。要求时间负责度为O(n)。
*使用动态规划方法来实现:
*如果用函数f(i)表示以第i个数字结尾的子数组的最大和,那么我们需要求出max(f[0...n])。
*我们可以给出如下递归公式求f(i)
* |-- array[i] 如果i==0或者f(i-1)<0
*f(i)=|
* |-- f(i-1) + array[i] 如果f(i-1)>0
*这个公式的意义:
* 当以第(i-1)个数字为结尾的子数组中所有数字的和f(i-1)小于0时,如果把这个负数和第i个数相加,得到的结果反而不第i个数本身还要小,所以这种情况下最大子数组和是第i个数本身。
* 如果以第(i-1)个数字为结尾的子数组中所有数字的和f(i-1)大于0,与第i个数累加就得到了以第i个数结尾的子数组中所有数字的和。
*/
1 public static int maxSumInSubArray(int[] array) { 2 int[] c = new int[array.length];// 用来记录以当前元素结尾(数组就到当前元素的位置为止)的子数组的最大和 3 int max = -1000;// 用来记录数组c[]中的最大值 4 int start = 0;// 记录数组中子数组的最大和的开始位置 5 int end = 0;// 记录数组中子数组的最大和的结束位置 6 int tmp = 0; 7 8 c[0] = array[0]; 9 for (int i = 1; i < array.length; ++i) { 10 if (c[i - 1] > 0) { 11 c[i] = c[i - 1] + array[i]; 12 } else { 13 c[i] = array[i]; 14 tmp = i; 15 } 16 if (c[i] > max) { 17 max = c[i]; 18 start = tmp; 19 end = i; 20 } 21 } 22 System.out.println("子数组最大和的起始位置:" + start + "~" + end); 23 return max; 24 }