思路来自算法导论,将数组平分为左右两个子数组,那么最大子数组可能在左边的子数组中,也有可能在右边的子数组中,还有可能跨过中间的元素,只有这三种情况。对于前两种情况,可以使用递归求解,对于第三种情况,可以做到用线性时间复杂度的函数来求解,详见代码。
#include <iostream>
#include <map>
using namespace std;
//the thought of this algrithm is devide-and-couque
int int_max = 0x7fffffff;//int类型的最大值,二进制最前面一位代表符号
int int_min = 0x80000000;//int类型的最小值
struct array_data{
int low;
int high;
int sum;
};
array_data* find_max_subarray(int* A, int low,int high);
array_data* find_max_crossing_subarray(int* A, int low, int high);
//find the max subarray which crosses middle element
//这段代码的复杂度是线性的(O(n))
array_data* find_max_crossing_subarray(int* A, int low, int high){
int mid = (low+high) >> 1;
int left_sum = int_min;
int sum = 0;
int max_left = 0;//初始点的选取无所谓,因为数组的和肯定比int_min要大
//从中间开始依次往左边找sum最大的子树组
for(int i=mid; i>=low; i--){
sum = sum + A[i];
if(sum > left_sum){
left_sum = sum;
max_left = i;
}
}
//从中间开始依次往右边找sum最大的子树组
int right_sum = int_min;
int max_right = mid+1;//初始认为中间往右第一个元素的位置为最大子树组的终点
sum = 0;
for(int i=mid+1; i<=high; i++){
sum = sum + A[i];
if(sum > right_sum){
right_sum = sum;
max_right = i;
}
}
array_data* arr = new array_data();
arr->low = max_left;
arr->high = max_right;
arr->sum = left_sum + right_sum;
return arr;
}
array_data* find_max_subarray(int* A,int low,int high){
if(low == high){
array_data* arr = new array_data();
arr->low = low;
arr->high = high;
arr->sum = A[low];
return arr;//base case: only one element
}else{
int mid = (low+high) >> 1;
//recursion left
array_data* arr_left = find_max_subarray(A,low,mid);
//recursion right
array_data* arr_right = find_max_subarray(A,mid+1,high);
//calc crossing middle
array_data* arr_cross = find_max_crossing_subarray(A,low,high);
//compare three situation
int left_sum = arr_left->sum;
int right_sum = arr_right->sum;
int cross_sum = arr_cross->sum;
if(left_sum >= right_sum && left_sum >= cross_sum){
return arr_left;
}else if(right_sum >= left_sum && right_sum >= cross_sum){
return arr_right;
}else{
return arr_cross;
}
}
}
int main(){
int A[] = {-1,2,4,-2,-4,4,9,-3,2};//注意初始化时必须是数组
int low = 0;
int high = sizeof(A)/sizeof(A[0])-1;
array_data* arr_done = find_max_subarray(A,low,high);
//output A[]
for(int i=0;i<= high;i++){
cout<<A[i]<<" ";
}
cout<<endl;
cout<<"low:"<<arr_done->low<<" high:"<<arr_done->high<<" sum:"<<arr_done->sum<<endl;
return 0;
}