leetcode hot 100 53 最大子数组和

题目链接

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 = [5,4,-1,7,8]
输出:23

提示:

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

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

分析及AC代码

好简单的dp,无需多言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
vector<int>dp(n);
int ans = nums[0];
for(int i=0;i<n;i++){
if(i == 0){
dp[i] = nums[i];
}else{
dp[i] = max(dp[i-1] + nums[i], nums[i]);
}
ans = max(ans, dp[i]);
}
return ans;
}
};

再思考一下进阶的分治做法

感觉用分治写有点多此一举,就当锻炼思维了。核心在于 可以将 区间分为 左区间,右区间,还有一个跨区间。左区间和右区间的起点和终点容易确定。中间跨区间由中心向两边枚举即可。时间复杂度 O(nlogn) ,比 dp 的O(n) 更久。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
int find_max(int l, int r, vector<int>& nums) {
if (l == r) {
return nums[l];
}
if (r - l + 1 == 2) {
return max(max(nums[l], nums[r]), nums[l] + nums[r]);
}
int mid = (l + r) >> 1;
int l_subarr_max = find_max(l, mid, nums);
int r_subarr_max = find_max(mid, r, nums);
int across_max = nums[mid];
int l_p = mid - 1, r_p = mid + 1;
int l_sum = nums[l_p], r_sum = nums[r_p];
int l_max = l_sum, r_max = r_sum;
while (l_p > l) {
l_p--;
l_sum += nums[l_p];
l_max = max(l_max, l_sum);
}
while (r_p < r) {
r_p++;
r_sum += nums[r_p];
r_max = max(r_max, r_sum);
}
across_max = across_max + l_max + r_max;
return max(across_max, max(l_subarr_max, r_subarr_max));
}

int maxSubArray(vector<int>& nums) {
return find_max(0, nums.size() - 1, nums);
}
};