2.8 KiB
2.8 KiB
题目地址
https://leetcode-cn.com/problems/maximum-subarray/
思路
暴力解法
暴力解法的思路,第一层for 就是设置起始位置,第二层for循环遍历数组寻找最大值
时间复杂度:O(n^2) 空间复杂度:O(1)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT32_MIN;
int count = 0;
for (int i = 0; i < nums.size(); i++) { // 设置起始位置
count = 0;
for (int j = i; j < nums.size(); j++) { // 每次从起始位置i开始遍历寻找最大值
count += nums[j];
result = count > result ? count : result;
}
}
return result;
}
};
贪心解法
贪心解法,其实不是很好理解, 看上面暴力的解法是两层for循环,那如何省掉一层for循环呢
贪心贪的是哪里呢?
如果 -2 1 在一起,计算起点的时候,一定是从1开始计算,因为负数只会拉低总和,这就是贪心贪的地方!
同样的道理,遍历nums,从头开始用count累积,如果count一旦加上nums[i]变为负数,那么就应该从nums[i+1]开始从头累积count了(也就是此时count要归0),因为已经变为负数的count,只会拖累总和。
相当于是不断调整区间的起始位置。
那有同学问了,区间终止位置不用调整么? 如何才能得到最大子序和呢?
区间的终止位置,其实就是如果count取到最大值了,用result记录一下就可以了。
如动画所示:
红色的起始位置就是贪心每次取count为正数的时候,开始一个区间的统计。
不难写出如下C++代码(关键地方已经注释)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT32_MIN;
int count = 0;
for (int i = 0; i < nums.size(); i++) {
count += nums[i];
if (count > result) { // 取区间累计的最大值(相当于不断确定最大子序终止位置)
result = count;
}
if (count <= 0) count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
}
return result;
}
};
时间复杂度:O(n) 空间复杂度:O(1)
我是程序员Carl,组队刷题可以找我,本文leetcode刷题攻略已收录,更多精彩算法文章尽在:代码随想录,期待你的关注!