子数组的最大和及系列问题
子数组的最大累加和问题
给定一个数组arr,返回子数组的最大累加和。
例如,arr=[1,-2,3,5,-2,6,-1],所有的子数组中,[3,5,-2,6]可以累加出最大的和12,所以返回12。
思路
时间复杂度O(n)
使用max记录当前和的最大值和sum记录当前的和
- sum < 0 -> 舍弃前面的,sum = 当前值
- sum >= 0 -> 累加
每次更新完sum,要更新max
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static int getMaxSum(int[] a) { //记录当前的和 int sum = 0; //记录最大值 int maxNum = Integer.MIN_VALUE; for (int i = 0; i < a.length; i++) { //如果和小于0,说明加上正数或会变大,但是仍然起副作用 //因此直接丢掉,使得sum为当前值,注意不是0,因为可能所有数字都是负数 if (sum < 0) { sum = a[i]; } else { //和大于0,可以继续累加 sum += a[i]; } //每次算完和,要更新max,这样才能记录下最大值 maxNum = Math.max(maxNum, sum); } return maxNum; }
|
找到两个不相容子数组的最大和
给定一个数组arr,其中有很多的子数组,找到两个不相容子数组使得相加的和最大,并返回和的最大值。
比如,数组[1,-1,0,-2,3,5,-2,8,7,-4],两个不相容子数组分别为[3,5]和[8,7]时累加和最大,所以返回23。
再比如,数组[3,-1,0,-2,3,5,-2,8,7,-4],两个不相容子数组分别为[3]和[3,5,-2,8,7]时累加和最大,所以返回24。
思路
借鉴上面的思路,做一些变形
设置两个数组
- left[i]表示[0,i]上的子数组最大和
- right[i]表示[i,N-1]上子数组的最大和
然后设置分割点k分别计算left[k]+right[k+1]最大值
该值表示[0,i]和[i+1,N-1]中最大值的和,既保持了不相交,也算出了最大值
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public static int getUnconnetedSum(int[] a){ int[] left = new int[a.length]; int[] right = new int[a.length]; int sum = 0; int maxNum = Integer.MIN_VALUE; //用求子数组最大和方法初始化left for (int i = 0; i < a.length; i++) { if(sum < 0){ sum = a[i]; }else{ sum += a[i]; } maxNum = Math.max(maxNum, sum); left[i] = maxNum; } sum = 0; maxNum = Integer.MIN_VALUE; //用求子数组最大和方法初始化right for(int i = a.length-1; i >= 0; i--){ if(sum < 0){ sum = a[i]; }else{ sum += a[i]; } maxNum = Math.max(maxNum, sum); right[i] = maxNum; } int res = Integer.MIN_VALUE; //以i为分界点,查找最大值 for (int i = 0; i < a.length-1; i++) { res = Math.max(res, left[i]+right[i+1]); } return res; }
|
子矩阵的最大累加和问题
给定一个矩阵matrix,其中的值有正、有负、有0,返回子矩阵的最大累加和。 例如,矩阵matrix为:
-90 48 78
64 -40 64
-81 -7 66
其中,最大累加和的子矩阵为:
48 78
-40 64
-7 66
所以返回累加和209。
再例如,matrix为:
-1 -1 -1
-1 2 2
-1 -1 -1
其中最大累加和的子矩阵为:
2 2
所以返回累加和 4。
思路
利用最大子数组求和的思想
先用tmp[i]求出在该行i列上所有数字的和,是一个列加的和,不停的用上一行列加tmp
有了tmp再求最大子数组和,就是求出选那些列能组成最大和
为了遍历所有的行,需要设置分割点,即先遍历0123…N,然后123…N,234..N
把所有可能都遍历到
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public static int getMaxtrixSum(int[][] a) { int maxNum = Integer.MIN_VALUE; //分割点i,遍历所有的行 for(int i = 0; i < a.length; i++){ //存放该行以上所有的和,即tmp[i]表示i列在该行的所有值的和 int[] tmp = new int[a[0].length]; //可遍历第012,12,2行 for(int k = i; k < a.length; k++){ //求最大子数组和的过程 int curSum = 0; for(int j = 0; j < a[0].length; j++){ //先更新tmp,然后求最大 tmp[j] += a[k][j]; if(curSum < 0){ curSum = tmp[j]; }else{ curSum += tmp[j]; } maxNum = Math.max(curSum, maxNum); } } } return maxNum; }
|