您的位置:首页 > 其它

求最大子数组之和及其一些扩展问题

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]所用,所以可以用一个元素代替一个数组

代码如下:

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,只包含一部分数组,将问题转化为不跨越的,求子数组的和为负数且绝对值最大的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: