题目
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
来源:力扣(LeetCode)
纠错1:
第一个方法暴力解,提交以后时间复杂度超时了。。。
此外,在边界数组中的检验修改了好多次,比如[-1,2],[-1,-2],[-1]
本人吸取总结教训和经验:
- 检验时考虑边界的特殊情况,比如数组里只有一个或两个元素,全为负数等
- 对于求和类。int sum = 0 有负数风险,不如一开始初始化为nums[0];或者单独定义一个result变量去返回值
- 对于for循环不清楚边界的问题,在旁边备注一个例子测试一下可取边界
- 写函数时不要忘了写返回值。。。
- for循环嵌套要厘清逻辑,尽量最多两层嵌套
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n=nums.size();//2
int sum=nums[0];
if (n==1)
return nums[0];
for (int i=0; i<n; i++)//0-1
{
for (int j=n-1; j>0; j--)//1
{
//long int subsum=std::accumulate(nums.begin()+i,nums.end()-j,0);
int subsum=0;
for (int m=i,n=j;m<=n;m++)//
{
subsum+=nums[m];
if ( sum < subsum )
sum = subsum;
};
};
};
return sum;
};
};
修改1:
超出时限- -考虑其他思路
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int numsSize=int(nums.size());
int result = INT_MIN;//#includ<limits>
for (int i=0; i<numsSize; i++)
{
int sum = 0;
for (int j=i; j<numsSize; j++)
{
sum+=nums[j];
if (result < sum)
result = sum;
};
};
return result;
};
};
动态规划1:
需要注意的地方:
- for循环的每条语句厘清逻辑,目的是什么,得到的值是什么
- 返回变量的初始值设定问题,个人感觉还是设为数组[0]比较好,避免了数组只有一个元素的情况,逻辑上也不太容易出现漏洞
- 变量命名上,注意一下如,maxSubArray
- 用到一些库函数,如max
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int numsSize=int(nums.size());
//int result = INT_MIN;//声明成理论意义上的极值避免在if判断比较中出现逻辑漏洞
int result = nums[0];
//vector<int> maxSumArray(numsSize);//vector动态内存管理,这里仿佛不必要
int maxSumArray[numsSize];//简单的累加,已知空间大小
//maxSumArray.pushback(nums[0]) ;
maxSumArray[0] = nums[0];
for (int i=1; i<numsSize; i++)
{
maxSumArray[i]=max(maxSumArray[i-1]+nums[i], nums[i]);//#include<algorithm>,容易漏掉只有nums只有一个值的情况
result= max(maxSumArray[i],result);
};
return result;
};
};
动态规划的进一步优化:
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
int numsSize = int(nums.size());
//因为只需要知道dp的前一项,我们用int代替一维数组
int dp(nums[0]);
int result = dp;
for (int i = 1; i < numsSize; i++)
{
dp = max(dp + nums[i], nums[i]);
result = max(result, dp);
}
return result;
}
};
更进一步的简化:
cppclass Solution
{
public:
int maxSubArray(vector<int> &nums)
{
int n(nums.size());
int sum2(nums[0]);
int result = sum2;
for (int i=1; i<n; i++)
{
/* 不如直接使用max函数效率高
int sumTemp(sum2+nums[i]);
if (sumTemp < nums[i])
sum2 = nums[i];
else
sum2 = sumTemp;*/
sum2 = max(sum2+nums[i], nums[i]);
//result = max(sum2, result);不如直接判断效率高:
if (result < sum2)
result = sum2;
}
return result;
}
};
贪心法1:
注意点:
- 初始值的设定一直是个问题,设定不好很容易在边界问题上出错,比如只有一个或两个元素的数组。这里的sum2设初值为0,因为在for循环中,sum2一开始就是从nums[0]开始累加的。而result是在后续的max中比较得到,这里的比较元素就是sum2和自身,因此自身的初始化也得有含义,这里要么是理论意义上的最小值,要么是初值。
- 再说一下贪心的思想,贪心就是sum2 本来是 不断累加,然后每一次累加都与上一次的result比较得出新的result。在逻辑上,sum2累加后要是小于零的话还不如直接用下一个值(也就是0加下一个nums[i]),所以这里贪心的核心思想就是:sum2小于零时归零(result保留着清零前各步中保留的最大值)
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
int n(nums.size());
int sum2(0);
int result(nums[0]);
for (int i=0; i<n; i++)
{
sum2+= nums[i];
result=max(sum2,result);
if (sum2<0)
sum2=0;
}
return result;
}
};