分治法求最大子序列和

写在前面,有个疑问,这种算法好像数组长度只能是偶数,但实际是奇数也可以,没想明白,改天在考虑。
第一个自己写的分治法的题,有点小激动,hoho~~
思路:
分治,分治,一个是分:不断将大问题分解为两个小问题,一直分解,直到解决这个问题比原来要轻松很多。
一个是治,将两个子问题合起来。
先将数组一分为二,求出左半部分的最大子序列和,求出右半部分的最大子序列和,最后求出横跨中间的最大子序列和,比较一下,输出大的那个。
一直分下去,直到只有一个元素,这时就不用计算中间了,直接判断这个数是否大于0,是返回这个数,不是就返回0(0就是一个也不选,空集也是子序列嘛),这样就把一个O(n^2)的问题(不考虑在线法)转化为O(n)的问题了,注意这里只是分,分治之后时间复杂度是O(NlogN)。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
int Max3(int i,int j,int k){
    int a[3];
    a[0]=i;
    a[1]=j;
    a[2]=k;
    sort(a,a+3);
    return a[2];
}
int MaxSubSum(int *a, int left, int right){
    int LeftMaxSum,RightMaxSum;//存放左边、右边最大和
    int MaxLeftBorderSum=0,MaxRightBorderSum=0;//存放中间向左最大和,存放中间往右最大和
    int LeftBorderSum=0,RightBorderSum=0;//临时记录从中间向左、向右的和
    if(left == right){//只有一个元素的情况
        if(a[left]>0)
            return a[left];
        else
            return 0;
    }
    int center = (left+right)/2;
    LeftMaxSum = MaxSubSum(a,left,center);
    RightMaxSum = MaxSubSum(a,center+1,right);

    //横跨两边的最大和
    for(int i = center;i>=left;i--){
        LeftBorderSum += a[i];
        if(LeftBorderSum > MaxLeftBorderSum)
            MaxLeftBorderSum = LeftBorderSum;
    }
    for(int i = center+1;i<=right;i++){
        RightBorderSum += a[i];
        if(RightBorderSum > MaxRightBorderSum)
            MaxRightBorderSum = RightBorderSum;
    }
    return Max3(LeftMaxSum,RightMaxSum,MaxLeftBorderSum+MaxRightBorderSum);
}
int main(){
    int a[] = {4,-3,5,-2,-1,2,6,-2};
    cout << MaxSubSum(a,0,7);
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页