求最大子数组之和及其一些扩展问题
2014-04-13 23:12
330 查看
最大子数组之和问题算是非常经典的问题,这里mark一下,以便以后回顾。
先说说二分,设数组为A[start...end],mid = (start + end)>>2,则有3种情况。1.落在start和mid之间,记为left;2.落在mid和end之间,记为right;3.落在中间,则必然包含A[mid],可在O(n)内解决记为middle。所以result=max(left,right,middle),时间复杂度为O(nlgn)
动态规划,以数组的第一个元素为例。A[0]及最大的一段记为A[i]...A[j]。那么有三种情况:
1.i=j=0
2.i=0<j
3.0<i<j
记nAll[0]表示以0开始最大的,那么nAll[0]为上面三种中最大的,用nStart[i]记为以i开始的最大子数组之和。则nAll[0]=max{A[0], A[0]+nStart[1], nAll[1]}。
因为nAll[k+1],nStart[k+1]只被nAll[k]和nStart[k]所用,所以可以用一个元素代替一个数组
代码如下:
扩展问题:
1.二维的最大子数组之和。
思路是将二维的转化为一维的,对行考虑每种情况,行选取完了后 ,就只剩列的,就变成了一维问题,然后用上面的解法。
2.一维的,手尾连续
有两种情况:
1.结果不跨越手尾,按照上面的解法
2.结果跨越手尾,两种情况
2.1,包含所有数组
2.2,只包含一部分数组,将问题转化为不跨越的,求子数组的和为负数且绝对值最大的
先说说二分,设数组为A[start...end],mid = (start + end)>>2,则有3种情况。1.落在start和mid之间,记为left;2.落在mid和end之间,记为right;3.落在中间,则必然包含A[mid],可在O(n)内解决记为middle。所以result=max(left,right,middle),时间复杂度为O(nlgn)
动态规划,以数组的第一个元素为例。A[0]及最大的一段记为A[i]...A[j]。那么有三种情况:
1.i=j=0
2.i=0<j
3.0<i<j
记nAll[0]表示以0开始最大的,那么nAll[0]为上面三种中最大的,用nStart[i]记为以i开始的最大子数组之和。则nAll[0]=max{A[0], A[0]+nStart[1], nAll[1]}。
因为nAll[k+1],nStart[k+1]只被nAll[k]和nStart[k]所用,所以可以用一个元素代替一个数组
代码如下:
import java.util.Random; /** * 求最大的连续子数组之和 * 数据为随机生成的5-15个数 * @author JeremyCai * */ public class MaxSum { /** * 动态规划,时间复杂度为O(n) * @param A * @return * 1.最大值:如果都为负数,则返回最大的负数,如果有0,则返回最后一次出现的0 * 2.开始位置 * 3.结束位置 */ public Info maxSum(int[] A){ int length = A.length; int nStart = A[length - 1]; int nAll = A[length - 1]; int start = length - 1, end = length - 1, ostart = length - 1, oend = length - 1; for(int i = length - 2; i >= 0; i--){ //nStart = max(A[i], nStart + A[i]) if(nStart < 0){ nStart = 0; start = i; end = i; } else start = i; nStart = nStart + A[i]; //nAll = max(nAll, nStart); if(nStart > nAll){ nAll = nStart; ostart = start; oend = end; } } return new Info(nAll, ostart, oend); } public static void main(String[] args){ MaxSum maxSum = new MaxSum(); Random random = new Random(); int length = random.nextInt(10) + 5; int[] A = new int[length]; for(int i = 0; i < length; i++){ A[i] = random.nextInt(15); if(random.nextBoolean()) A[i] = -A[i]; System.out.print("A["+i+"]="+A[i]+" "); } Info result = maxSum.maxSum(A); System.out.println("\n"+result); } class Info{ int sum; int start; int end; public Info(int sum, int start, int end){ this.sum = sum; this.start = start; this.end = end; } public int getSum() { return sum; } public int getStart() { return start; } public int getEnd() { return end; } public String toString(){ return "Sum=" + sum + " start" + start + " end" + end; } } }
扩展问题:
1.二维的最大子数组之和。
思路是将二维的转化为一维的,对行考虑每种情况,行选取完了后 ,就只剩列的,就变成了一维问题,然后用上面的解法。
2.一维的,手尾连续
有两种情况:
1.结果不跨越手尾,按照上面的解法
2.结果跨越手尾,两种情况
2.1,包含所有数组
2.2,只包含一部分数组,将问题转化为不跨越的,求子数组的和为负数且绝对值最大的
相关文章推荐
- 最大子数组问题及其变形
- 编程之美2.14扩展问题1 求子数组和的最大值(首尾可以相连)
- 《编程之美》读书笔记(十二):“求数组的子数组之和的最大值”扩展问题
- 编程之美寻找数组中的最大值和最小值以及扩展问题
- 编程之美 求数组的子数组之和的最大值(包含扩展问题解答)
- 求子数组之和的最大值——编程之美 2.14 扩展问题 正确实现
- HDU1003+数组最大子序列和及其扩展(循环数组,二维矩阵等)
- 求子数组之和的最大值——编程之美 2.14 扩展问题 正确实现
- 编程之美2.10寻找数组中的最大值和最小值扩展问题Java版
- 求数组的子数组之和的最大值及扩展问题2
- 编程之美2.14 子数组之和的最大值 扩展问题(首尾相连)
- 编程之美2.14扩展问题2 求数组的子数组之和的最大值并给出子数组的起始终止位置
- 编程之美2.14扩展问题2 求数组的子数组之和的最大值并给出子数组的起始终止位置
- 编程之美--求数组的子数组之和的最大值--扩展问题
- 编程之美2.14扩展问题1 求子数组和的最大值(首尾可以相连)
- 二分图最大匹配问题及其扩展
- 连续子数组的最大和问题及其变化
- 经典的求数组中最大值及其位置的问题.
- 编程之美2.14扩展问题1 求子数组和的最大值(首尾可以相连)
- 最大子数组和的扩展问题