53.最大子序和

题目描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例 1:

1
2
3
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

1
2
输入:nums = [1]
输出:1

示例 3:

1
2
输入:nums = [0]
输出:0

示例 4:

1
2
输入:nums = [-1]
输出:-1

示例 5:

1
2
输入:nums = [-100000]
输出:-100000

提示:

  • 1 <= nums.length <= 3 * 10^4
  • -10^5 <= nums[i] <= 10^5

进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

题解

动态规划

没有很好的思路,参考的官方题解……

思路大概是这样:把数组的第一个元素先当做最大和,然后开始遍历数组,如果当前指针的前一个数字大于零,则将它加到现在指针所指向的值;否则不对数组做任何更新操作。然后取出数组中的最大元素并返回。

我理解为:在遍历过程中,正数是有益于寻找最大和的,所以遇到正数时,就将其进行向后累加;而遇到负数时,其对结果是不利的,所以会到此为止。
例如:

1
2
3
4
//原序列
nums = [-2,1,-3,4,-1,2,1,-5,4]
//遍历后的序列
nums = [-2,1,-2,4,3,5,6,1,5]

遍历后的序列上的每一位数字表示当前位置具有的连续子数组最大和。所以返回整个数组的最大值即可。

1
2
3
4
5
6
7
8
9
10
class Solution {
public int maxSubArray(int[] nums) {
int maxRes = nums[0];
for(int i = 1; i < nums.length; i++)
if(nums[i - 1] > 0)
nums[i] += nums[i - 1];
Arrays.sort(nums);
return nums[nums.length - 1];
}
}

我的题解:时间复杂度:O(2n); 空间复杂度:O(1)


官方的题解是这样的:

1
2
3
4
5
6
7
8
9
10
class Solution {
public int maxSubArray(int[] nums) {
int pre = 0, maxAns = nums[0];
for (int x : nums) {
pre = Math.max(pre + x, x);
maxAns = Math.max(maxAns, pre);
}
return maxAns;
}
}

官方题解的巧妙之处在于,在遍历数组的时,同时做了两件事:1.使用pre指针更新数组;2.使用maxAns一直指向更新数组的最大值,最后直接返回maxAns即可。

时间复杂度:O(n); 空间复杂度:O(1)