zoukankan      html  css  js  c++  java
  • 分治法求连续子数组的最大和

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

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

    去吧,去吧,到彼岸去吧,彼岸是光明的世界!
  • 相关阅读:
    js学习总结----多级菜单jquery版本
    js学习总结----案例之多级菜单js版本
    js学习总结----案例之百度搜索框
    js学习总结----案例之放大镜
    js学习总结----事件委托和事件代理(鼠标点击其他地方隐藏效果)
    js学习总结----鼠标跟随js版
    js学习总结----案例之鼠标跟随jquery版
    js学习总结----事件的传播机制
    js学习总结----事件基础
    js学习总结----jquery版本轮播图及extend扩展
  • 原文地址:https://www.cnblogs.com/lengyue365/p/5080388.html
Copyright © 2011-2022 走看看