时间复杂度:o(nlgn)
分治法求最大子数组关键的问题在于如果去划分递归,当把原数组分解为规模相近的两个子数组的时候,当前数组的最大子数组只会在三种情况之一出现,要么最大子数组出现在左边子数组,要么最大子数组出现在右边子数组,要么就出现在横跨两子数组相交结点的连续子数组,前两种情况是比待求问题更小的子问题,可直接用递归求得,最后一种情况中要使得子数组最大,那必然是左侧取最大,右侧取最大的合并。这样,只需分别遍历交点左右两侧求得最大子数组即可。在三种情况下求得的最大子数组再取一个最大的就是当前数组的最大子数组了。
代码:
/*************************************************************************
> File Name: max_sub_array.cpp
> Author sangoly
> Mail: sangoly@aliyun.com
> Created Time: 2014年07月07日 星期一 15时50分15秒
************************************************************************/
#include<iostream>
#include<limits>
using namespace std;
class Range {
public:
int start;
int end;
int sum;
Range(int mStart, int mEnd, int mSum) : start(mStart), end(mEnd), sum(mSum) {}
bool operator>(Range& other) const {
return this->sum > other.sum;
}
};
Range* find_max_crossing_subarray(int list[], int start, int middle,
int end) {
int left_sum = numeric_limits<int>::min();
int sum = 0;
int l_start;
for (int i = middle; i >= start; i--) {
sum += list[i];
if (sum > left_sum) {
left_sum = sum;
l_start = i;
}
}
int right_sum = numeric_limits<int>::min();
sum = 0;
int r_end;
for (int i = middle + 1; i <= end; i++) {
sum += list[i];
if (sum > right_sum) {
right_sum = sum;
r_end = i;
}
}
return new Range(l_start, r_end, left_sum + right_sum);
}
Range* max_sub_array(int list[], int start, int end) {
if (start == end)
return new Range(start, end, list[start]);
int middle = (start + end) / 2;
Range* max_range_left = max_sub_array(list, start, middle);
Range* max_range_right = max_sub_array(list, middle + 1, end);
Range* max_range_crossing_middle = find_max_crossing_subarray(list, start, middle, end);
if ((*max_range_left > *max_range_right)
&& (*max_range_left > *max_range_crossing_middle)) {
delete max_range_right;
delete max_range_crossing_middle;
return max_range_left;
}
else if ((*max_range_right > *max_range_left)
&& (*max_range_right > *max_range_crossing_middle)) {
delete max_range_left;
delete max_range_crossing_middle;
return max_range_right;
}
else {
delete max_range_left;
delete max_range_right;
return max_range_crossing_middle;
}
}
int main() {
int list[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5,
-22, 15, -4, 7};
Range* max_range = max_sub_array(list, 0, sizeof(list) / sizeof(int) - 1);
cout<<"The max sub array's index from "<<max_range->start<<" to "
<<max_range->end<<endl;
cout<<"The max sub array value is "<<max_range->sum<<endl;
return 0;
}