最大子串(leetcode053-Maximum Subarray)【动态规划】

最大子串(leetcode053-Maximum Subarray)

leetcode053-题目地址

本文仅仅记录的是我子集对题目的理解,可能有不对的地方。

题目的大意是,给定一个非空的整数数组,找到一个最大子串满足,这个子串中的所有数字之和是所有子串中最大的。

最开始的错误代码是这样的:

// 第一遍写的错误代码
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sum = nums[0];
        for(int i=1; i<nums.size(); i++){
            if(sum+nums[i] > sum) sum=sum+nums[i];//-----(1)
        }
        return sum;
    }
};

我思路很简单,sum用来记录当前最大子串的数值,从左到右遍历数组,如果sum+nums[i] > sum,则把位置i处的数计入子串。这里犯了很大的错误,if语句中的sum+nums[i] > sum等价于nums[i] > 0,也就是说我这段代码是在统计数组中所有非负数的和。

现在来分析一下题意,用cursum记录当前(前i个元素)的最大和,cursum = max(cursum + nums[i], nums[i])这个式子用代码可以写成:

if(cursum + nums[i] > nums[i]) cursum = cursum + nums[i];
//等价于: if(cursum > 0) cursum = cursum + nums[i]; 

也就是说,

当cursum是个正数,

  • nums[i] > 0,肯定要把这个数算进来
  • nums[i] < 0,那么给这个nums[i]一个机会,以防后面有更大的正数。也就是说这个nums[i]虽然暂时减少了子串的数值,但是它可以连接后面的数。

当cursum是个负数,

  • nums[i] > 0,丢弃cursum,cursum = nums[i],也就是从nums[i]开始重新计数
  • nums[i] < 0,如果nums[i] > cursum,从nums[i]开始计数。

所以,同时,要用一个变量res来存储整个过程中的最大子串的数值。res记录整个过程中cursum的最大值。

最后AC的代码是:

class Solution {
public:
    int maxSubArray(vector<int> &nums) {
       int res = nums[0];
       int cursum = nums[0];
       for(int i=1; i<nums.size(); i++){
            if(cursum > 0) cursum += nums[i];
            else cursum = nums[i];
            if(cursum > res) res = cursum;
       }
       return res;
    }
};

下面这个代码是别人的:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res = INT_MIN, curSum = 0;
        for (int num : nums) {
            curSum = max(curSum + num, num);
            res = max(res, curSum);
        }
        return res;
    }
};

下面是写的比较好的讲解:

动态规划解析 https://blog.csdn.net/linhuanmars/article/details/21314059

https://blog.csdn.net/Pwiling/article/details/49405163

猜你喜欢

转载自www.cnblogs.com/Elaine-DWL/p/9755907.html