Leetcode53:Maximum Subarray求最大子串和

题目解析:求出一个含负数的数组中和最大的子串,输出这个最大的和。

解法1——动态规划

以nums=[-2,1,-3,4,-1,2,1]为例,考虑动态规划的求解:

递推方程为:sum[i] = max{ nums[i], nums[i] + sums[i+1] } 表示为从第i个元素开始的最大子串和。

即:

nums-21-34-121
sum(从后向前计算)2436231

代码实现为:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        int sum, maxSum;
        sum = maxSum = nums[n-1];
        
        for(int i=n-2;i>=0;--i){
            sum = max(nums[i],nums[i]+sum);
            maxSum = max(maxSum,sum);
        }
        
        return maxSum;
    }
};

动态规划的时间复杂度为O(n)。耗时11ms。

解法2:来源于http://blog.youkuaiyun.com/joylnwang/article/details/6859677,采用卡耐基梅隆大学Jay Kadane给出的一个线性时间算法。该算法的思想是:对一个数组array[1...n]求其最大子串和,有两个结论:

1)对于array[1...n],如果array[i...j]就是满足和最大的子串,那么对于任何k(i<=k<=j),我们有array[i...k]的和大于0。因为如果存在k使得array[i...k]的和小于0,那么我们就有array[k+1...j]的和大于array[i...j],这与我们假设的array[i...j]就是array中和最大子串矛盾。

2)其次,我们可以将数组从左到右分割为若干子串,使得除了最后一个子串之外,其余子串的各元素之和小于0,且对于所有子串array[i...j]和任意k(i<=k<j),有array[i...k]的和大于0。此时我们要说明的是,满足条件的和最大子串,只能是上述某个子串的前缀,而不可能跨越多个子串。我们假设array[p...q],是array的和最大子串,且array[p...q],跨越了array[i...j],array[j+1...k]。根据我们的分组方式,存在i<=m<j使得array[i...m]的和是array[i...j]中的最大值,存在j+1<=n<k使得array[j+1...n]的和是array[j+1...k]的最大值。由于array[m+1...j]使得array[i...j]的和小于0。此时我们可以比较array[i...m]和array[j+1...n],如果array[i...m]的和大于array[j+1...n]则array[i...m]>array[p...q],否array[j+1...n]>array[p...q],无论谁大,我们都可以找到比array[p...q]和更大的子串,这与我们的假设矛盾,所以满足条件的array[p...q]不可能跨越两个子串。对于跨越更多子串的情况,由于各子串的和均为负值,所以同样可以证明存在和更大的非跨越子串的存在。对于单元素和最大的特例,该结论也适用。

由上述算法的结论可以得到本题解答的思路:把整个数组从左到右只要元素(累加)为负则分成一个子串,最后一个子串可正可负,分割成子串的同时求出各个子串的最大前缀和。如果整个数组全部都是负数,只需要找到这些负数中最大的元素即可。代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        int sum=0,maxsum;
        maxsum = nums[0];
        
        for(int i=0;i<n;++i){
            sum += nums[i];
            if(maxsum < sum)
                maxsum = sum;
            if(sum<0)
                sum = 0;    // 分下一组子串
            
        }
        
        return maxsum;
    }
};
时间复杂度也是O(n),但耗时13ms,比动态规划更慢一点。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值