给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
1.动态规划
解题思路:利用辅助数组s[],记录到当前位置为止的最大子序和(必须包含当前位置)
关于辅助数组的计算:s[i] = (i-1 >= 0) ? (s[i-1] < 0 ? nums[i] : s[i-1] + nums[i]) : nums[i];
主要在于s[i-1] < 0 ? nums[i] : s[i-1] + nums[i],如果到当前位置的前一位置为止的最大子序和小于0(即s[i-1] < 0),则应该从当前位置重新计算子序和(即s[i] = nums[i]),因为如果累加的话,则一定有s[i] < s[i-1],因此当s[i-1] < 0时,需从当前位置重新计算子序和。
java代码:
class Solution {
public int maxSubArray(int[] nums) {
int[] s = new int[nums.length];
int maxsum = Integer.MIN_VALUE;
for(int i = 0; i < nums.length; i++){
s[i] = (i-1 >= 0) ? (s[i-1] < 0 ? nums[i] : s[i-1] + nums[i]) : nums[i];
maxsum = Math.max(s[i], maxsum);
}
return maxsum;
}
}
2.分治
解题思路:将数组二分为两部分nums1[]、nums2[],则最大子序和一定是下面三种情况中的一种:
- 最大子序和在nums1[]中
- 最大子序和在nums2[]中
- 最大自序和跨越nums1和nums2,此时需计算nums1[]中从右端点开始(包含右端点)的最大子序和和nums2[]中从左端点开始(包含左端点)的最大自序和,求这两个最大自序和之和
java代码:
class Solution {
public int maxSubArray(int[] nums) {
return maxSubSum(nums, 0, nums.length-1);
}
private int maxSubSum(int[] nums, int start, int end){
int sum = Integer.MIN_VALUE;
if(start > end)
return 0;
if(start == end)
return nums[start];
int middle = (start + end) >> 1;
int leftMax = maxSubSum(nums, start, middle);
int rightMax = maxSubSum(nums, middle+1, end);
int leftSub = nums[middle], rightSub = nums[middle+1];
int leftTmp = leftSub, rightTmp = rightSub;
for(int i = middle-1; i >= start; i--){
leftTmp += nums[i];
leftSub = Math.max(leftSub, leftTmp);
}
for(int i = middle+2; i <= end; i++){
rightTmp += nums[i];
rightSub = Math.max(rightSub, rightTmp);
}
sum = Math.max(sum, leftMax);
sum = Math.max(sum, rightMax);
sum = Math.max(sum, leftSub+rightSub);
return sum;
}
}