LeetCode算法题:最大子序和maxSubArray

给定一个整数数组 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;
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_43777983/article/details/89349941