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的。所以有必要指定一个初始值。