前言:这是我们大学社团给我们大一新生布置的每日一题任务,因为本人编程理解有限,参考价值较低。
求最大连续子数组和的问题,比较经典的一个问题。我在尝试用题目本意去解题的过程中,很神奇的AC了,短时间解释不好,那我来讲个解决这个问题的大体思路吧,这个方法在算法竞赛中很常用,我建议如下分步理解:
第一步:暴力
很明显嘛,我去枚举一下所有连续子序列(先说一下这个会超时)不就好了?
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int L = nums.size(),ans=nums[0];
for(int i=0;i<L;i++){
for(int j=i;j<L;j++){
int t=0;
for(int k=i;k<=j;k++){
t+=nums[k];
}
ans = max(ans,t);
}
}
return ans;
}
};
第二步:用累加和法优化
既然会超时,那我们优化一下。先这么想:我们求一下数组每一项的累加和,设它为数组sum[] ,我们所要求的区间的累加和就是sum[j]-sum[i-1]了不是吗awa,代码如下(还是超时):
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int L = nums.size(),ans=nums[0];
for(int i=1;i<L;i++){
nums[i] += nums[i-1];
ans = max(ans,nums[i]);
}
for(int i=1;i<L;i++){
for(int j=i;j<L;j++){
ans = max(ans,nums[j]-nums[i-1]);
}
}
return ans;
}
};
第三步:用玄学优化
虽然我们已经避开了O(n^3)的暴力,但是O(n^2)的累加和方法也会超时,那么通用的方法就到此结束了,接下来开始的是玄学(bushi)做题时间awa
当我们在遍历数组的时候,用一个临时变量t去存储从前到此元素的最优解,那么这个最优解应该怎么去找呢?先看几种情况下我们应有的思路:
①数列中没有负数
这个情况很容易理解,我们到每一个元素的最优解都是前面所有数值包括这个数字的累加和
②数列全是负数
这个情况就要让我们考虑到ans的初始值可以是nums[0]或-identfy,我们在求最优解时遇到前面所有项累加和的时候,若这个累加和小于0,就要重置为0,并且不能让ans与它比较。
所以我们得到了如下的AC代码:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int L = nums.size(),ans=nums[0],t=0;
for(int i=0;i<L;i++){
t = max(0,t+nums[i]);
ans = max(ans,nums[i]<0?nums[i]:t);
}
return ans;
}
};
为什么看起来比之前两个解法简单呢?我也解释不清~