给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释:连续子数组[4,-1,2,1] 的和最大,为6
暴力求解的话,第一层是n个元素的循环,第二层是每个元素与其后面的所有元素之和,记录最大值。共计算 n n * n2 n 2 次,时间复杂度O(n 2 2 )
借鉴自discuss
观察可发现,当第 Xi X i 数的值大于 X0 X 0 ~ Xi−1 X i − 1 之和时,就应该抛弃 X0 X 0 ~ Xi−1 X i − 1 d的和(但是不代表该sum值不是最大值,只是开始新的计算);反之, Xi X i 的值由 X0 X 0 ~ X−1 X − 1 之和代替
比如说:[-2,1,-3,4,-1,2,1,-5,4]
【暂未使用Junit写单元测试】
public class MaxSumSubArray {
public static int maxSumValueSubArray(int[] nums) {
int max = nums[0];
if (nums.length == 1) {
return max;
}
for (int i = 0; i < nums.length - 1; i++) {
nums[i + 1] = Math.max(nums[i + 1], nums[i] + nums[i + 1]);
max = Math.max(max, nums[i + 1]);
}
return max;
}
public static void main(String[] args) {
int[] nums1 = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
int[] nums2 = {-5, 4};
int[] nums3 = {6, -2, 0};
System.out.println(MaxSumSubArray.maxSumValueSubArray(nums3));
}
}
优于82.72%的提交结果
public class MaxSumSubArrayDivideTest {
@Test
public void testMaxSubArrayDivide_1() throws Exception {
MaxSumSubArrayDivide maxSumSubArrayDivide = new MaxSumSubArrayDivide();
int[] nums = {-3};
int expected = nums[0];
assertEquals("Wrong!Missmatch!", expected, maxSumSubArrayDivide.maxSubArray(nums));
}
@Test
public void testMaxSubArrayDivide_2() throws Exception {
MaxSumSubArrayDivide maxSumSubArrayDivide = new MaxSumSubArrayDivide();
int[] nums = {-2,1,-3,4,-1,2,1,-5,4};
int expected = 6;
assertEquals("Wrong!Missmatch!", expected, maxSumSubArrayDivide.maxSubArray(nums));
}
}
public class MaxSumSubArrayDivide {
public int maxSubArray(int[] nums) {
if (nums.length == 1) {
return nums[0];
} else return maxSubArrayDivide(nums, 0, nums.length - 1);
}
private int maxSubArrayDivide(int[] nums, int from, int to) {
// 递归出口
if (from == to) {
return nums[from];
}
int middle = (from + to) / 2;
// left recursive call
int left = maxSubArrayDivide(nums, from, middle);
// right recursive call
int right = maxSubArrayDivide(nums, middle + 1, to);
// 开始O(n)时间复杂度的计算,"叶子"返回后,需要计算第三种可能:左半部分的后缀+右半部分的前缀之和为最大值
int leftEnd = nums[middle], leftSuffix = leftEnd;
int rightBegin = nums[middle + 1], rightPrefix = rightBegin, i = 1;
// 计算左半部分的最大后缀
while (middle - i >= from) {
leftEnd += nums[middle - i++];
leftSuffix = Math.max(leftSuffix, leftEnd);
}
// 计算右半部分的最大前缀
i = 2;
while (middle + i <= to) {
rightBegin += nums[middle + i++];
rightPrefix = Math.max(rightPrefix, rightBegin);
}
int join = leftSuffix + rightPrefix;
return Math.max(left, Math.max(right, join));
}
}