leetcode-master/problems/0053.最大子序和.md

2.8 KiB
Raw Blame History

题目地址

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刷题攻略已收录,更多精彩算法文章尽在:代码随想录,期待你的关注!