求数组的子数组之和的最大值
题目描述:
一个有N个整数元素的一维数组(A[0],A[1],A[2],......,A[n-1]),在众多子数组中,最大的子数组值为多少。
例如数组为[1,-2,3,10,-4,7,2,-5],其中最大子数组为[3,10,-4,7,2],输出结果为18
思路一:蛮力法
基本思想就是遍历所有可能的子数组,然后互相比较求出最大值,效率很低,算法复杂度为O(N2)
// 最基本的方法,也是效率最低的方法,时间复杂度为O(N2)
public int MaxSubArray(int[] A) {
int sum, max = A[0], begin = 0, end = 0;
for (int i = 0; i < A.length; i++) {
sum = 0;
for (int j = i; j < A.length; j++) {
sum += A[j];
if (sum > max)
max = sum;
}
}
return max;
}
思路二:分治思想
如果将数组分成相等长度的两段数组(A[0],......,A[n/2-1])和(A[n/2].....,A[n-1]),分别求出这两段数组各自的最大子数组,则原数组的最大子数组可能的情况为以下三种:
1、(A[0],A[1],A[2],......,A[n-1])的最大子数组和(A[0],.......,A[n/2-1])的最大子数组相同
2、(A[0],A[1],A[2],......,A[n-1])的最大子数组和(A[n/2].....,A[n-1])的最大子数组相同
3、(A[0],A[1],A[2],......,A[n-1])的最大子数组跨过其中间两个元素A[n/2-1]到A[n/2]
第1种和第2种情况实际上就是问题规模减半的相同子问题,可以通过递归求得
第3种情况,需要从前段数组中找到以A[n/2-1]结尾的最大子数组s1,从后段数组中找到以A[n/2]开头的最大子数组s2,那么第3种情况的最子数组值为s1+s2,只需要对原数组遍历一次即可
// 分治法
public int maxmaxSubArray(int[] A, int left, int right) {
if (left > right)
return 0;
if (left == right)
return A[left];
int mid = (left + right) >> 1;
int leftsumborder = A[mid], leftsum = 0;
for (int i = mid; i >= left; i--) {
leftsum += A[i];
leftsumborder = Math.max(leftsum, leftsumborder);
}
int rightsumborder = A[mid + 1], rightsum = 0;
for (int i = mid + 1; i <= right; i++) {
rightsum += A[i];
rightsumborder = Math.max(rightsum, rightsumborder);
}
int leftmaxsum = maxmaxSubArray(A, left, mid);
int rightmaxsum = maxmaxSubArray(A, mid + 1, right);
return Math.max(Math.max(leftmaxsum, rightmaxsum),(leftsumborder + rightsumborder));
分治思想将算法的时间复杂度由原来的O(N2)降低到O(N*log2N)
思路三:动态规划思想
可以考虑数组的第一个元素A[0],以及最大的一段数组(A[i],....,A[j])与A[0]之间的关系,有以下三种情况:
1、当0=i=j时,元素A[0]本身构成和最大的一段
2、当0=i<j时,和最大的一段以A[0]开始
3、当0<i时,元素和最大的一段没有关系
由上述分析,可以将一个大问题转化为一个较小的问题。假设已经知道(A[1],......,A[n-1])中和最大的一段数组之和为maxsum[1],并且已经知道(A[1],......,A[n-1])中包含A[1]的最大的一段数组为temp[1],那么根据上述分析的三种情况,可得(A[0],A[1],A[2],......,A[n-1])问题转换为max{A[0],A[0]+temp[1],maxsum[1]}
public int MaxSubArray(int[] A) {
int maxsum = A[0], temp = A[0];
for (int i = 0; i < A.length; i++) {
if (temp < 0)
temp = A[i];
else
temp += A[i];
if (maxsum < temp)
maxsum = temp;
}
return maxsum;
}
动态规划方法的时间复杂度为O(N)