给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
刚拿到题的思路是用穷举法,用双层循环把所有可能性列举出来,找到其中的最大值,时间复杂度O(n*n),这种方法效率太低。
题中提示可以用分治法与时间复杂度O(n)的解法。
分治法的思想即把整个数组分为左、右两部分,左右两部分各又分为左、右两部分(递归),直至左右两部分只为一个元素位置,然后逐层的找到最大子列和,最后得出结论。时间复杂度为O(nlogn)。
代码参考:
https://www.cnblogs.com/sunnysola/p/4795691.html
private static int maxSumRec(int [] a , int left , int right){
if( left == right ){//边界①
if( a[left] > 0 )
return a[left];
else
return 0;
}
//递归分治部分②
int center = (left + right) / 2;
int maxLeftSum = maxSumRec( a, left, center);
int maxRightSum = maxSumRec( a, center + 1, right);
//对改层的部分进行数据处理③
int maxLeftBorderSum = 0, leftBorderSum = 0;
for( int i = center; i >= left; i--){
leftBorder += a[i];
if( maxLeftBorderSum < leftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
int maxRightBorderSum = 0, leftBorderSum = 0;
for( int i = center + 1; i <= right; i ++){
rightBorderSum += a[i];
if( maxRightBorderSum > rightBorderSum)
maxRightBorderSum = rightBorderSum;
}
//返回
return max3( maxRightBorderSum + maxLeftBorderSum , maxLeftSum , maxRightSum);
}
时间复杂度O(n)的解法的思路为:
1.一个数组如果有正数,那么最大子列和的开始和结尾肯定都是正数。
2.利用1的结论,可以利用一层循环找到第一个正数,然后从它开始向后相加(没找到之前就找最大的那个负数),从而找到最大子列和。代码如下:
public int maxSubArray(int[] nums) {
int max_Sum=nums[0];
int cur_Sum=0;
for(int i=0;i<nums.length;i++){
if(cur_Sum<=0){
cur_Sum=nums[i];
}else{
cur_Sum+=nums[i];
}
if(cur_Sum>max_Sum){
max_Sum=cur_Sum;
}
}
return max_Sum;
}
}