最大子数组问题

在leetcode上看到的求最大子数组问题,在算法导论上分治策略章节中也有相同的问题,在这里介绍两种算法。
第一种,用分治法的思想去求解,先将数组对半分,那么,最大子数组的位置有三种情况,1.子数组全部在中点的右边,2.子数组全部在中点的左边。3.子数组部分在中点的左边,另一部分在中点的右边。
只要分别求出这三种情况的最大值比较,取最大的即为最大子数组。
第三种情况最简单只要从中点出发,向左递减,向右递增。分别找出左右和的最大值即可。下面是代码

int maxArr(int *arr,int start,int length)
{
    int sum1 = 0,sum2 = 0,max1 = arr[(length +start)/ 2],max2 = arr[(length + start) / 2];
    /* 求出中点左边到中点的和的最大值 */
    for(int i = (length + start)/ 2;i >= start;i--)
    {
        sum1 += arr[i];
        if(sum1 > max1)
            max1 = sum1;
    }
    /* 求出中点右边到中点的和的最大值 */
    for(int i = (length + start)/ 2;i < length;i++)
    {
        sum2 += arr[i];
        if(sum2 > max2)
            max2 = sum2;
    }
    return max1 + max2 - arr[(length + start) / 2];
}

那么在中点右边和左边怎么求呢。其实就是求中点左边的数组的最大子数组。这样依然是上述的三种情况。那么就把原数组分成了一个较小的数组。只须递归求解。中点右边也是相同的思想。
这个算法的思想是记录目前为止已经处理过的最大子数组。若已知a[1…j]的最大子数组,那么a[1…j+1]的最大子数组要么是a[1…j]的最大子数组,要么是摸个子数组a[i…j+1]。

int subMax(int *arr,int start,int length)
{
    int max1 = maxArr(arr,start,length);//求出第三种情况的最大值
    /* 求出第一种情况的最大值 */   
    if(((length + start) / 2 - 1) >= start)
        {
            int max2 = subMax(arr,start,(length + start) / 2);
            if(max2 > max1)
                max1 = max2;
        }
        /* 求出第二种情况的最大值 */
    if(((length + start) / 2 + 1) < length)
        {
            int max3 = subMax(arr,(length + start) / 2 + 1,length);
            if(max3 > max1)
                max1 = max3;
        }
    return max1;
}

用这种方法的求解时间复杂度为o(nlgn),下面介绍一种时间复杂度为o(n)的算法。
下面用c++实现。

int maxSubArray(vector<int>& nums) {
        int max = nums[0],j = 1,sum = nums[0];
        while(j < nums.size())
        {
            if(nums[j] > max)
            max = nums[j];
            if((sum + nums[j]) < (nums[j] + nums[j - 1]))
                sum = nums[j] + nums[j - 1];
            else
                sum += nums[j];
             if(sum > max)
            max = sum;
            j++;
        }
点赞