#53 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.

题解

比较经典的一个问题,是学习的好材料

解1:穷举,O(n²)复杂度,意料中的超时。

public class Solution {
    public int maxSubArray(int[] nums) {
        int subsum;
        int maxsum=nums[0];//注意这里不是int maxsum=<strong>0</strong>;
        int len=nums.length;
        for(int i=0;i<len;i++){
            subsum=0;
            for(int j=i;j<len;j++)
            subsum+=nums[i];
            maxsum=Math.max(subsum,maxsum);
        }
        return maxsum;
    }
}

解2:&&Kadane算法 

这是我的解法。和Kadane算法 相似有没有,很激动有没有!由于相似,所以放在一起说明了。

首先有这样的结论,对于nums[1,...,n],如果nums[i,...,j]是满足和最大的子串,那么对于任意的i=<k<=j,有nums[i,...,k]的和大于0。利用一个数组sum[i]记录局部子串和。遍历数组,对于i,若sun[i-1]>0,则将nums[i]加入之前子串,并记录子串和sum[i]=sun[i-1]+nums[i],否则nums[i]单开子串,记录子串和sum[i]=nums[i]。最后维护一个全局最大值max,即使返回的最大子串和。

public class Solution {
    public int maxSubArray(int[] nums) {
        int[] sum = new int[nums.length];
        int maxsub = nums[0];
        sum[0] = nums[0];
        for(int i = 1; i < nums.length; i++){
            sum[i] = Math.max(nums[i], sum[i - 1] + nums[i]);
            maxsub = Math.max(maxsub, sum[i]);
        }
        return maxsub;
     }
}

Kadane算法

理:将数组从左到右分割为若干子串,使得除了最后一个子串之外,其余子串的各元素之和小于0,且对于所有子串nums[i...j]和任意k(i<=k<j),有nums[i...k]的和大于0。满足条件的和最大子串,只能是上述某个子串的前缀,而不可能跨越多个子串。

原理详细可参考:http://blog.csdn.net/joylnwang/article/details/6859677

执行流程:从头到尾遍历目标数组,将数组分割为满足上述条件的子串,同时得到各子串的最大前缀和,然后比较各子串的最大前缀和,得到最终答案。

以array={-2, 1, -3, 4, -1, 2, 1, -5, 4}为例,通过遍历,可以将数组分割为如下3个子串(-2),(1,-3),(4,-1,2,1,-5,4),这里对于(-2)这样的情况,单独分为一组。各子串的最大前缀和为-2,1,6,所以目标串的最大子串和为6。

public class Solution {
    public int maxSubArray(int[] nums) {
          int max_ending_here = 0;
          int max_so_far = nums[0];
          
          for(int i = 0; i < nums.length; i++){  
              if(max_ending_here < 0) 
                   max_ending_here = 0;  
              max_ending_here += nums[i];  
              max_so_far = Math.max(max_so_far, max_ending_here);   
         }  
         return max_so_far; 
     }
}


解3:分治法:

最大子串和的区间有以下三种情况(low,high分别为左右边界,mid为(low+high)/2):(1) 区间完全在 A[low,mid-1];(2) 区间完全在 A[mid+1,high];(3) 区间包含有 A[mid],等价于从中间元素开始往左累加的最大值 + 从中间元素开始往右累加的最大值

public class Solution {
    public int maxSubArray(int[] nums) {
           return divide(nums, 0, nums.length-1); 
      }
    public int divide(int nums[], int low, int high){  
          if(low == high)
              return nums[low];  
          if(low == high-1)  
              return Math.max(nums[low]+nums[high], Math.max(nums[low], nums[high]));
             
         int mid = (low+high)/2;  
         int lmax = divide(nums, low, mid-1);  
         int rmax = divide(nums, mid+1, high); 
         
         int mmax = nums[mid];  
         int tmp = mmax;  
         for(int i = mid-1; i >=low; i--){  
             tmp += nums[i];  
             if(tmp > mmax)
                 mmax = tmp;  
         }  
         tmp = mmax;  
         for(int i = mid+1; i <= high; i++){  
             tmp += nums[i];  
             if(tmp > mmax)
                 mmax = tmp;  
         }  
         return Math.max(mmax, Math.max(lmax, rmax));  
     }
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值