[LeetCode][简单算法][动态规划] 最大子序和

https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/23/dynamic-programming/56/

 

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

 

这道题目主要有循环法O(n)和递归归并法O(nlogn)。

递归的方法,还是采用分治的思想,把数组分为两半,两半再分别分为两部分。。。。。

这道题里面又如何应用这种思想呢?

我们知道,如果我们把数组分为两部分,最大子序和出现有三种情况:1,在左侧;2,在右侧;3,横跨左右两侧。

所以,对每一个作为我们递归函数处理对象的数组来说,我们都需要计算出它左侧,右侧和中间的最大子序和再加以比较。其中,横跨中间的最大子序和,可以看做由中间下标为一端,向左和向右的最大子序和相加。

由此我们可以写出代码:

int getMaxSum(int l, int r, int* nums){
    
    if(l==r){
        return nums[r];
    }
    
    int c = (l+r)/2;
    
    int left_max = getMaxSum(l,c,nums);
    int right_max = getMaxSum(c+1,r,nums);
    
    int left_mid=0, right_mid=0, lm_max=nums[c], rm_max=nums[c+1];
    int i;
    for(i=c;i>=l;i--){
        left_mid += nums[i];
        if(left_mid>lm_max)
            lm_max = left_mid;
    }
    for(i=c+1;i<=r;i++){
        right_mid += nums[i];
        if(right_mid>rm_max)
            rm_max = right_mid;
    }
    
    return max3(left_max, right_max, lm_max+rm_max);
    
}

int max3(int a, int b, int c){
    if(a>=b&&a>=c){
        return a;
    }else if(b>=a&&b>=c){
        return b;
    }else if (c>=a&&c>=b){
        return c;
    }else{
        return a;
    }
}



int maxSubArray(int* nums, int numsSize) {
    return getMaxSum(0,numsSize-1,nums);
}

第二种O(n)的方法,真的是很轻巧了。

int maxSubArray(int* nums, int numsSize) {
   int i=0, cur_sum=0,max_sum=nums[0];
    
    for(i=0;i<numsSize;i++){
        cur_sum += nums[i];
        if(cur_sum>max_sum)
            max_sum = cur_sum;
        if(cur_sum<0)
            cur_sum=0;
    }
    return max_sum;
}

 这种方法的效率比前一种要高,在执行结果上就体现出来了。

关键在于if(cur_sum>0) cur_sum=0; 这一部分。

也就是说,如果之前的子序和降到了0以下,我们就把它舍弃,重新开始。因为无论如何,一个和为负数的子序对后续的子序列只有害而无益,丢掉它才能得到更大的子序和。

详细一些的说明可以参考https://my.oschina.net/itblog/blog/267860

另外要注意一点的是变量的初始值,不是所有编译器都会把没有变量初始化为0的。所以有必要指定一个初始值。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值