最大子数组问题求解的是给定一个数组a[0...n-1],求出它的一个子数组使得其所有元素的和加起来最大
如果使用暴力解法即枚举所有的子数组,则时间复杂度为O(n^2)
采用分治法,对一段数组a[low.....high],求它的最大子数组,mid = (low+high)/ 2
那么,a[low..high]的子数组有可能有三种分布的情况,假设子数组的上下届为i,j
1) 在a的左部分,即 low < = i <= j < = mid
2) 在a的右部分,即 mid + 1 <= i <= j <= high
3) 跨越mid,即 low <= i <= mid <= j <= high
下面给出基于此思想的分治算法
注:要对一个数组a[0...n-1]求其最大子数组和,调用的是find_max_subarray(a,0,n-1)
#include <iostream>
#include <limits.h>
using namespace std;
struct temple {
int left;
int right;
int sum;
};
temple max_crossing_subarr ( int* a, int low, int mid, int high) {
int left_sum = INT_MIN;
int right_sum = INT_MIN;
int sum;
int max_left = low;
int max_right = high;
//找左边的
sum = 0;
for ( int i = mid; i >= low; --i ) {
sum += a[i];
if ( sum > left_sum ) {
left_sum = sum;
max_left = i;
}
}
//找右边的
sum = 0;
for ( int i = mid+1; i <= high; ++i ) {
sum += a[i];
if ( sum > right_sum ) {
right_sum = sum;
max_right = i;
}
}
temple t = { max_left, max_right, left_sum + right_sum };
return t;
}
temple find_max_subarray ( int*a, int low, int high ) {
if ( high == low ) {
temple t;
t.left = low;
t.right = high;
t.sum = a[low];
return t;
}
else {
int mid = ( high + low ) / 2;
temple left_temple = find_max_subarray(a,low,mid);
temple right_temple = find_max_subarray(a,mid+1,high);
temple cross_temple = max_crossing_subarr(a,low,mid,high);
if ( left_temple.sum >= right_temple.sum
&& left_temple.sum >= cross_temple.sum ) {
return left_temple;
}
else if ( right_temple.sum >= left_temple.sum
&& right_temple.sum >= cross_temple.sum ) {
return right_temple;
}
else {
return cross_temple;
}
}
}
int main()
{
// int a[] = { 13, -3, -25, 20, -3, 16, -23, 18, 20, -7, 12
// -5, 22, 15, -4, 7};
int a[] = {-5,1,2,5,-3,7,-10};
temple t = find_max_subarray(a,0,sizeof(a)/sizeof(int)-1);
cout << t.sum << endl;//结果12
return 0;
}