最大子序列和问题

求数组的最大子序列和

方法一

给定了一个数组让我们求他的最大子序列和,我们最容易想到的方法就是暴力枚举的方式

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int thisMax = 0, sumMax = nums[0];
        int len = nums.size();

        for(int i = 0; i < len; ++i){
            thisMax = 0;
            for(int j = i; j < len; ++j){
                thisMax += nums[j];
                sumMax = max(sumMax, thisMax);
            }
        }

        return sumMax;
    }
};

上述的时间复杂度为O(N^2),当数据量很大的时候就会非常的慢

方法二

利用分治的方式,将数组不断的递归划分成子问题。最大的会等于左边的、右边的、跨边界的三者之一

int getMax(int arr[], int l, int r){
    if(l >= r){
        return arr[l];
    }

    int mid = l + r >> 1;
    int maxLeft = getMax(arr, l, mid);
    int maxRight = getMax(arr, mid + 1, r);

    //因为要跨边界,所以直接从边界处扫描过去,所以下面就是从mid处一路扫描过去的最大值(这里的最大值是会和边界连续的)
    int maxLeft1 = arr[mid], thisMax = 0;
    for(int i = mid; i >= l; --i){
        thisMax += arr[i];
        maxLeft1 = max(maxLeft1, thisMax);
    }

    thisMax = 0; int maxRight1 = arr[mid + 1];
    for(int i = mid + 1; i <= r; ++i){
        thisMax += arr[i];
        maxRight1 = max(maxRight1, thisMax);
    }

    int t = maxLeft1 + maxRight1;
    return (maxLeft > maxRight? (maxLeft > t? maxLeft : t) : (maxRight > t? maxRight : t));
}

时间复杂度为:O(NlogN)

方法三

利用Kadane算法(也就是动态规划)
当前面的子序列和小于0的时候就不用了舍弃掉,用也只会使得后续序列变小,重新选择起点的意思。
每一步都进行最大值的比较,这样即使系列和没有以前的大,也会使得前面序列和的值保存了到最大值变量中。

int getMax(int arr[], int n){
    int maxSum = arr[0];
    for(int i = 1; i < n; ++i){
        if(arr[i - 1] > 0) arr[i] += arr[i - 1];//大于0的加的有意义
        maxSum = max(maxSum, arr[i]);
    }

    return maxSum;
}

int getMax(int arr[], int n){
    int maxSum = arr[0], thisMax = arr[0];
    for(int i = 1; i < n; ++i){
        thisMax = max(thisMax + arr[i], arr[i]);//意思就是,如果thisMax使得arr[i]变小了,就不取他,让thisMax重新选择起点
        maxSum = max(thisMax, maxSum);
    }

    return maxSum;
}

上述两种是一个意思,第一个是在数组原地操作,而第二个多用了一个临时变量
时间复杂度为:O(N),是线性的

posted @ 2020-02-28 14:05  Lngstart  阅读(161)  评论(0编辑  收藏  举报