lc最大子序和
作者:互联网
输入:
[-2,1,-3,4,-1,2,1,-5,4]
输出:
6
解的序列【4,-1,2,1】
方法一:贪心:
思想:
如果当前所指元素之前的序列和(cur)小于0,则丢弃之前的序列max=nums[i],如果当前所指元素之前的序列和(cur)大于0,则当前元素加上之前的序列和,max=cur+nums[i]
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int cur=nums[0];
int maxs=nums[0];//初始化
for(int i=1;i<nums.size();i++)
{//遍历
cur=max(nums[i],cur+nums[i]);//计算当前和,如果上一个cur是负数,那么当前cur应该为nums[i]即舍弃前面的,如果上一个cur是正数,那么新的cur=以前的cur+nums[i];
maxs=max(cur,maxs);//最大和应该取以前的最大值和当前的cur中的最大
}
return maxs;
}
};
方法二:动态规划:
用f(i)表示以下标i为结尾的最大子序列和;
那么最大序列和max=max(f(i)) i=1…n;
其中f(i)=max(f(i-1)+nums[i],nums[i])
这里也可以理解如果f(i-1)>0;那么nums[i]=f(i-1)+nums[i] ;否则还是nums[i]自身最大。
int maxSubArray(vector<int>& nums) {
for(int i=1;i<nums.size();i++)
{
if(nums[i-1]>0)
nums[i]+=nums[i-1];//动态规划递推式
}
int maxs=nums[0];
for(int j=1;j<nums.size();j++)//求最大的nums[i]
{
if(nums[j]>maxs)
maxs=nums[j];
}
return maxs;
}
方法三:分治:
计算(l,r)之间的最大子序列可以分治地求(l,m)以及(m+1,r)即将一个序列分为左右两部分;即m=(l+r)/2;不断的分下去直到每组只剩下一个元素,再考虑,是否要和左右合并其中:
lsum:是以l为左端点数组的最大序列和
rsum:是以r为右端点数组的最大序列和
maxsum:是(l,r)内的最大序列和
lrsum:是(l,r)的序列和
所以,以(l,m)、(m+1,r)为例
lrsum=[l,m].isum+[m+1,r].isum;//左区间+右区间
lsum=max([l,m].lsum , [l,m].lrsum+[m+1,r].lsum)左区间还是左+一部分右
rsum=max([m+1,r).rsum ,[l,m].rsum+[m+1,r].lrsum)右区间还是右区间+一部分左
maxsum=max(lsum,rsum,[l,m].rsum+[m+1,r].lsum),从左端点开始连续的一段还是右端点连续的一段还是中间连续的一段
struct Status {//定义结构体
int lsum, rsum, maxsum, lrsum;
};
Status merge(Status l,Status r)
{//合并两个status
int lrsum=l.lrsum+r.lrsum;
int lsum=max(l.lsum,l.lrsum+r.lsum);
int rsum=max(r.rsum,r.lrsum+l.rsum);
int maxsum=max(max(l.maxsum,r.maxsum),l.rsum+r.lsum);
return (Status){lsum,rsum,maxsum,lrsum};
}
Status sumlr(vector<int>& a,int l,int r)
{//计算以l,r为起始的数组的最大序列和
if(l==r)
return (Status){a[l],a[l],a[l],a[l]};
int m=(l+r)/2;
Status lstatus=sumlr(a,l,m);
Status rstatus=sumlr(a,m+1,r);
return merge(lstatus,rstatus);
}
int maxSubArray(vector<int>& nums)
{
return sumlr(nums,0,nums.size()-1).maxsum;//计算0-nums.size()-1之间的最大序列和
}
标签:最大,nums,int,max,rsum,cur,lsum,子序,lc 来源: https://blog.csdn.net/m0_44946030/article/details/113461123