💻 在线刷题 · 全屏 IDE 模式进入刷题模式 →
53. 最大子数组和
题目描述
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1] 输出:1
示例 3:
输入:nums = [5,4,-1,7,8] 输出:23
提示:
1 <= nums.length <= 105-104 <= nums[i] <= 104
进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。
方法一:动态规划
我们定义
考虑
也即:
由于
时间复杂度
可视化演示
以
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]为例,演示动态规划f = max(f, 0) + nums[i]的过程:f表示以当前元素结尾的最大子数组和,蓝色为当前计算的格子,绿色为已完成,红色为最大和所在位置。点击 ▶ 播放,或逐步操作。
i▼
f
-20
·1
·2
·3
·4
·5
·6
·7
·8
nums
-20
11
-32
43
-14
25
16
-57
48
当前计算比较/参照已计算回溯路径答案
初始化:f = nums[0] = -2,ans = -2。第一行 f 为状态数组,第二行 nums 为原数组。
1 / 9
java
class Solution {
public int maxSubArray(int[] nums) {
int ans = nums[0];
for (int i = 1, f = nums[0]; i < nums.length; ++i) {
f = Math.max(f, 0) + nums[i];
ans = Math.max(ans, f);
}
return ans;
}
}cpp
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int ans = nums[0], f = nums[0];
for (int i = 1; i < nums.size(); ++i) {
f = max(f, 0) + nums[i];
ans = max(ans, f);
}
return ans;
}
};ts
function maxSubArray(nums: number[]): number {
let [ans, f] = [nums[0], nums[0]];
for (let i = 1; i < nums.length; ++i) {
f = Math.max(f, 0) + nums[i];
ans = Math.max(ans, f);
}
return ans;
}python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
ans = f = nums[0]
for x in nums[1:]:
f = max(f, 0) + x
ans = max(ans, f)
return ans方法二:分治法
可视化演示
以
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]为例,演示分治法:递归maxSub(left, right)将区间对半分割,分别求左半、右半及跨中点的最大子数组和,取三者最大值返回。绿色区间为当前递归考察的区间。点击 ▶ 播放,或逐步操作。
l▼mid▼r▼
-20
11
-32
43
-14
25
16
-57
48
滑动窗口 [0, 8](绿色区域)
0非零交换中窗口内指针位置
maxSub(0, 8):mid = (0+8)>>1 = 4。分治:左半 [0..4],右半 [5..8],再分别求最大子数组和。
1 / 8
java
class Solution {
public int maxSubArray(int[] nums) {
return maxSub(nums, 0, nums.length - 1);
}
private int maxSub(int[] nums, int left, int right) {
if (left == right) {
return nums[left];
}
int mid = (left + right) >>> 1;
int lsum = maxSub(nums, left, mid);
int rsum = maxSub(nums, mid + 1, right);
return Math.max(Math.max(lsum, rsum), crossMaxSub(nums, left, mid, right));
}
private int crossMaxSub(int[] nums, int left, int mid, int right) {
int lsum = 0, rsum = 0;
int lmx = Integer.MIN_VALUE, rmx = Integer.MIN_VALUE;
for (int i = mid; i >= left; --i) {
lsum += nums[i];
lmx = Math.max(lmx, lsum);
}
for (int i = mid + 1; i <= right; ++i) {
rsum += nums[i];
rmx = Math.max(rmx, rsum);
}
return lmx + rmx;
}
}python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
def crossMaxSub(nums, left, mid, right):
lsum = rsum = 0
lmx = rmx = -inf
for i in range(mid, left - 1, -1):
lsum += nums[i]
lmx = max(lmx, lsum)
for i in range(mid + 1, right + 1):
rsum += nums[i]
rmx = max(rmx, rsum)
return lmx + rmx
def maxSub(nums, left, right):
if left == right:
return nums[left]
mid = (left + right) >> 1
lsum = maxSub(nums, left, mid)
rsum = maxSub(nums, mid + 1, right)
csum = crossMaxSub(nums, left, mid, right)
return max(lsum, rsum, csum)
left, right = 0, len(nums) - 1
return maxSub(nums, left, right)