输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
之前的思考:
//子数组意味着必须是连续的,不能排序
//要求连续的和最大
//特殊情况,全部为大于等于0的数,全部相加
//如果全为负数,那就排序后,返回第一个
//一旦出现穿插负数,先找有正数的位置
//有一个思想非常重要:最大子数组的第一个数一定是正数!!!最后一个数也一定是正数!
//否则直接把第一个数去掉就能组成更大的数
//另外最大子数组的前两个数相加一定是正数,不然直接舍弃掉就是最大值了
//同理:子数组的前任意n个数相加也一定是正数
首先明确某个数组本身也是它的子数组,其次运用动态规划的思想就能很容易解决,**把大问题看做为应该将下一个元素加入现有子数组还是应该让其作为新子数组的开头这个小问题的叠加,**并在分治解决小问题的过程中,同时保存出现的子数组的最大和的值,就能解决这个问题。
往往现有子数组为负数时,都会将新元素作为新子数组的开头 ,否则就加入原子数组。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sum=0;
int Max=INT_MIN;
for(auto num:nums)
{
if(sum<0 ||sum== 0)
{
sum=num;
}else
{
sum+=num;
}
Max=max(Max,sum);
}
return Max;
}
};
同样的思想,更简化的写法:
1.求出目前连续子序列的最大值pre
2.用res记录出现过的最大值
首先明确某个数组本身也是它的子数组,其次运用动态规划的思想就能很容易解决,**把大问题看做为应该将下一个元素加入现有子数组还是应该让其作为新子数组的开头这个小问题的叠加,**并在分治解决小问题的过程中,同时保存出现的子数组的最大和的值,就能解决这个问题。
怎么判断是应该作为是新子数组的开头还是加入上一个子数组,方法就是将新元素和加入新元素后的子数组进行大小比较,如果新的子数组更大,那就加入,如果新的元素更大,那就把它作为新的子数组开头。
往往现有子数组为负数时,都会将新元素作为新子数组的开头 ,否则就加入原子数组。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//pre用来保存现有子数组之和
//res用来保存最大的子数组之和
int pre = 0, res = nums[0];
for(int i : nums) {
//如果该数与前子数组相加变大了就加入选一个子数组,否则就作为新子数组的开头!
pre = max(pre + i, i);
res = max(res, pre);
}
return res;
}
};
还有一种时间复杂度大于O(n)的方法:
(链接:https://blog.csdn.net/qq_38358582/article/details/89389677)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
{
vector<int>SUM;
for(int i=0;i<nums.size();i++)
{
SUM.push_back(nums[i]);
}
for(int i=0;i<nums.size()-1;i++)
{
int sum=nums[i];
for(int j=i+1;j<nums.size();j++)
{
sum+=nums[j];
SUM.push_back(sum);
}
}
vector<int>::iterator max=max_element(SUM.begin(),SUM.end());
return *max;
}
}
};