【数组】Maximum Subarray

题目:

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray [4,−1,2,1] has the largest sum = 6.

click to show more practice.

More practice:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

思路:

方法一:动态规划, 数组为vec[],设dp[i] 是以vec[i]结尾的子数组的最大和,对于元素vec[i+1], 它有两种选择:a、vec[i+1]接着前面的子数组构成最大和,b、vec[i+1]自己单独构成子数组。则dp[i+1] = max{dp[i]+vec[i+1],  vec[i+1]}

附加:记录左右节点位置

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    var sum=0,maxsum=-2147483648,begin=0;
    for(var i=0,len=nums.length;i<len;i++){
        if(sum>=0){
            sum=sum+nums[i];
        }else{
            sum=nums[i];
            begin=i;
        }
        
        if(maxsum<sum){
            maxsum=sum;
            left=begin;
            right=i;
        }
    }
    
    return maxsum;
};

方法二

最简单的就是穷举所有的子数组,然后求和,复杂度是O(n^3)

int maxSum1(vector<int>&vec, int &left, int &right)
{
    int maxsum = INT_MIN, sum = 0;
    for(int i = 0; i < vec.size(); i++)
        for(int k = i; k < vec.size(); k++)
        {
            sum = 0;
            for(int j = i; j <= k; j++)
                sum += vec[j];
            if(sum > maxsum)
            {
                maxsum = sum;
                left = i;
                right = k;
            }
        }
    return maxsum;
}
 

算法三:

上面代码第三重循环做了很多的重复工作,稍稍改进如下,复杂度为O(n^2)

int maxSum2(vector<int>&vec, int &left, int &right)
{
    int maxsum = INT_MIN, sum = 0;
    for(int i = 0; i < vec.size(); i++)
    {
        sum = 0;
        for(int k = i; k < vec.size(); k++)
        {
            sum += vec[k];
            if(sum > maxsum)
            {
                maxsum = sum;
                left = i;
                right = k;
            }
        }
    }
    return maxsum;
}
算法四:
分治法, 下面贴上编程之美的解释, 复杂度为O(nlogn)

image

image

//求数组vec【start,end】的最大子数组和,最大子数组边界为[left,right]
int maxSum3(vector<int>&vec, const int start, const int end, int &left, int &right)
{
    if(start == end)
    {
        left = start;
        right = left;
        return vec[start];
    }
    int middle = start + ((end - start)>>1);
    int lleft, lright, rleft, rright;
    int maxLeft = maxSum3(vec, start, middle, lleft, lright);//左半部分最大和
    int maxRight = maxSum3(vec, middle+1, end, rleft, rright);//右半部分最大和
    int maxLeftBoeder = vec[middle], maxRightBorder = vec[middle+1], mleft = middle, mright = middle+1;
    int tmp = vec[middle];
    for(int i = middle-1; i >= start; i--)
    {
        tmp += vec[i];
        if(tmp > maxLeftBoeder)
        {
            maxLeftBoeder = tmp;
            mleft = i;
        }
    }
    tmp = vec[middle+1];
    for(int i = middle+2; i <= end; i++)
    {
        tmp += vec[i];
        if(tmp > maxRightBorder)
        {
            maxRightBorder = tmp;
            mright = i;
        }
    }
    int res = max(max(maxLeft, maxRight), maxLeftBoeder+maxRightBorder);
    if(res == maxLeft)
    {
        left = lleft;
        right = lright;
    }
    else if(res == maxLeftBoeder+maxRightBorder)
    {
        left = mleft;
        right = mright;
    }
    else
    {
        left = rleft;
        right = rright;
    }
    return res;
}
原文地址:https://www.cnblogs.com/shytong/p/5115781.html