给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
对于本题我们采用 分治 的思想:
对于最大子序列可能存在于数组的三个部分:左半边、右半边、中间。对于左半边与右半边我们可以采用递归调用函数来解决,对于寻找可能在中间的最大子序列,我们可以经以下几步:
- 从中间向左边界查找,将每次更新后的值与储存的最大值作比较,若 > 储存值,则说明当前项的值为正 或 累积值因先前遭遇负值减小后因新增的 ? 项正值 重新增大且较储存值更大,即查找到了新的最大子序列
- 从中间向右边界查找
- 加和向左查找与向右查找的结果
查找到中间的最大子序列后,我们仅需要与左右最大子序列进行比较即可得出最终结果,实现如下:
public int maxSubArray(int[] nums) {
return maxSubArray(0, nums.length-1, nums);
}
private static int maxSubArray(int left, int right, int[] nums) {
if (left == right) return nums[left];
int middle = (left+right) / 2;
int leftMax = maxSubArray(left, middle, nums);
int rightMax = maxSubArray(middle+1, right, nums);
// 注意设置最大查找值的初始值为起始项的值,下同
int leftSumMax = nums[middle], allLeftSum = 0;
for (int i = middle; i >= left; -- i) {
allLeftSum += nums[i];
leftSumMax = Math.max(allLeftSum, leftSumMax);
}
int rightSumMax = nums[middle+1], allRightSum = 0;
for (int j = middle+1; j <= right; ++ j) {
allRightSum += nums[j];
rightSumMax = Math.max(rightSumMax, allRightSum);
}
return Math.max(Math.max(leftMax, rightMax), leftSumMax+rightSumMax);
}