力扣日记:【贪心算法篇】53. 最大子数组和
日期:2024.3.16
参考:代码随想录、力扣
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 <= 10^5
- -10^4 <= nums[i] <= 10^4
进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。
题解
cpp
class Solution {
public:
#define SOLUTION 2
int maxSubArray(vector<int>& nums) {
#if SOLUTION == 1 /*暴力解法,超出时间限制*/
int maxSum = nums[0]; // 初始化为nums的第一个数
int curSum = 0;
for (int i = 0; i < nums.size(); i++) {
for (int j = i; j < nums.size(); j++) {
curSum += nums[j];
if (curSum > maxSum) {
maxSum = curSum;
}
}
curSum = 0; // 重置curSum
}
return maxSum;
#elif SOLUTION == 2 /*贪心算法*/
// 局部最优:计算"连续和",一旦当前"连续和"为负数,则丢弃"连续和"的所有元素,从下一个元素重新计算(因为前面的负数连续和只会让总和减小)
// 即不断调整最大子序和区间的起始位置
// 全局最优:选取最大"连续和"
// 局部最优的情况下,并记录最大的"连续和",可以推出全局最优。
int maxSum = nums[0];
int curSum = 0;
int index = 0;
while (index < nums.size()) { // 遍历到最后,由于及时记录了最大连续和,所以后面即时有负数值也不影响
curSum += nums[index];
if (curSum > maxSum) { // 更新最大连续和(curSum一定要先加上元素值再比较,不能重置为0后比较)
maxSum = curSum;
}
if (curSum < 0) { // 当前连续和为负数
curSum = 0; // 重置连续和为0,从下一个元素重新计算
}
index = index + 1; //
}
return maxSum;
#endif
}
};
复杂度
暴力解法(超时):
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
贪心算法:
- 时间复杂度:O(n)
- 空间复杂度:O(1)
贪心算法只需要一个for循环遍历完即可,所以时间复杂度是O(n)
思路总结
- 啊啊啊啊贪心算法好难啊,做一道不会一道 T^T,到底怎么想到局部最优啊......
- 关键:不能让"连续和"为负数的时候加上下一个元素,而不是 不让"连续和"加上一个负数。
- 所以要在当前"连续和"为负数的时候,调整最大子序列区间的起始位置为下一个元素(而不是在加上了一个负数的时候,因为只要当前连续和为正数,就对于增大总和是有利的)。
- 思路来源于代码随想录
- TODO:动态规划