分而治之:最大子数组问题
问题: 给出一个数组,找到一个子数组(连续的),使得该子数组的元素和是最大的。 输入: 给定一个数组X[1…n],对于任意一对数组下标为l,r(l≤r)的非空子数组,其和记为S(l,s). 输出: 求出S(l,s)的最最值,记为Smax .
问题分析
将数组X[1…n]分为X[1…n/2]和X[n/2 +1…n]递归求解子问题
S1∶数组X[1…n/2]的最大子数组
S2∶数组X[n/2+1…n]的最大子数组合并子问题,得到S
max S3∶跨中点的最大子数组 数组X的最太子数组之和S
max =max{S1,sz,s3}
执行效率的瓶颈值在合并方面,也就是S3的求解问题。
S3的求解:
记mid = n/2
S3可分为左右两部分 Left:以X[mid]为结尾的最大子数组之和 Right:以X[mid+1]为开头的最大子数组之和 S3 = Left + Right
Left的求解: 从X[mid]向前遍历求和,并记录最大值 Right的求解: 从X[mid +1]向后遍历求和,并记录最大值
S3的时间复杂度:
Left时间复杂度:O(mid)Right时间复杂度:O(n - mid)S3时间复杂度:O(n)
算法分析图
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std
;
const int N
= 10000;
int q
[N
];
int findMidSum(int l
, int mid
, int r
) {
int leftSum
= -100000, rightSum
= -100000;
int sum
= 0;
for (int i
=mid
; i
>=l
; i
--) {
sum
+= q
[i
];
leftSum
= max(leftSum
, sum
);
}
sum
= 0;
for (int i
=mid
+1; i
<=r
; i
++) {
sum
+= q
[i
];
rightSum
= max(rightSum
, sum
);
}
return leftSum
+ rightSum
;
}
int maxSubArr(int l
, int r
) {
if (l
== r
) return q
[l
];
int mid
= l
+ r
>> 1;
int leftSum
= maxSubArr(l
, mid
);
int rightSum
= maxSubArr(mid
+1, r
);
int midMaxSum
= findMidSum(l
, mid
, r
);
int res
= max(leftSum
, rightSum
);
res
= max(res
, midMaxSum
);
return res
;
}
int main() {
int n
;
cin
>> n
;
for (int i
=0; i
<n
; i
++) scanf("%d", &q
[i
]);
int res
= -100000;
res
= maxSubArr(0, n
-1);
cout
<< res
;
return 0;
}