分治法求连续子数组的最大和

思路来自算法导论,将数组平分为左右两个子数组,那么最大子数组可能在左边的子数组中,也有可能在右边的子数组中,还有可能跨过中间的元素,只有这三种情况。对于前两种情况,可以使用递归求解,对于第三种情况,可以做到用线性时间复杂度的函数来求解,详见代码。

#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;
}

去吧,去吧,到彼岸去吧,彼岸是光明的世界!
原文地址:https://www.cnblogs.com/lengyue365/p/5080388.html