最大子串(leetcode053-Maximum Subarray)
本文仅仅记录的是我子集对题目的理解,可能有不对的地方。
题目的大意是,给定一个非空的整数数组,找到一个最大子串满足,这个子串中的所有数字之和是所有子串中最大的。
最开始的错误代码是这样的:
// 第一遍写的错误代码
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