问题描述,给定一个数组A[0,1,...,n-1],求出A的连续数组,使得该子数组的和最大。
例如:数组A[1,-2,3,10,-4,7,2],则最大的子数组为[3,10,-4,7,2]
解法:
1.暴力法
2.分治法
3.动态规划法
一:暴力发
分析:直接求解A[i,...,j]的值,0<=i<=n;i<=j<=n,i,i+1,...,j-1的最大长度为n,时间复杂度为o(n^3)。
代码分析:
int maxSubArray_baoli(int A[], int n) {
int maxSum = A[0];
int currentSum;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
currentSum = 0;
for (int k = i; k < j; k++) {
currentSum += A[k];
}
if (currentSum > maxSum) {
maxSum = currentSum;
}
}
}
return maxSum;
}
二:分治法
分析:
(1)将数组从中间分开,那么最大子数组要么完全在左边数组,要么完全在右边数组,要么跨立在分界点上,仅此 三种情况。
(2)完全在左边数组或者右边数组时候,可以使用递归解决。
(3)跨立在分界点上时,最大子数组是在左边数组的最大后缀和右边数组左边的最大前缀之和,因此,从分界点向前和向后扫描即可得。算法时间复杂度可达到o(nlogn).
代码分析:
double maxSubArray_fenzhi(int A[], int left, int right) {
if (left == right)return A[left];
int middle = floor((left + right) / 2);
double m1 = maxSubArray_fenzhi(A, left, middle);
double m2 = maxSubArray_fenzhi(A, middle + 1, right);
int i, l_past = A[middle], now = A[middle];
for (i = middle - 1; i >= left; i--) {
now += A[i];
l_past = max(l_past, now);
}
int r_past = A[middle + 1];
now = A[middle + 1];
for (i = middle + 1; i <= right; i++) {
now += A[i];
r_past = max(r_past, now);
}
double m3 = l_past + r_past;
double temp = max(m1, m2);
return max(temp, m3);
}
double max(double x, double y) {
return (x > y) ? x : y;
}
3.动态规划
int maxSubArray_dongtaiguihua(int A[], int n) {
int result = A[0];
int sum = A[0];
for (int i = 0; i < n; i++) {
if (sum > 0)sum += A[i];
else sum = A[i];
if (sum > result)result = sum;
}
return result;
}