连续子串和

1、给出一个序列,求连续子串和的最大值,要求在O(n)求解

思路:积分图+两层for循环遍历起始位置和终止位置,O(n^2)

最优思路:依次累加,并不断更新Max,在累加的过程中,若sum小于0,更新开始位置。

其实这个更新位置我纠结很久,这里若第i位sum<0,sum从下一位开始累加求和。第i要是为正数怎么办?怎么可能,sum(i-1)+a[i]<0,sum(i-1)要求是大于0的,那么a[i]必定是负数。

int fun1(vector<int> a,int n){   //长度>=1
    int sum=0;
    int Max=-999;
    for(int i=0;i<n;i++){
        sum+=a[i];
        if(sum>Max) Max=sum;
        if(sum<0) sum=0;
    }
    return Max;
}

2、给出一个序列,求连续子串和的最大值的最大长度,要求在O(n)求解

思路:这个可以在最大连续子序列和的基础上进行操作,注意:最大长度,sum>=Max,等于也要判断是否出现MaxP,还要最重要的约束条件是,sum必须是小于0的时候才能更新位置。这样才能符合长度最长。(若最小长度,只需要在最大Max时候去最小的MaxP,同时sum<=0的时候进行位置更换,才符合最短长度)

int fun2(vector<int> a,int n){
    int sum=0;
    int Max=-999;
    int MaxP=0;
    int p=0;
    for(int i=0;i<n;i++){
        sum+=a[i];
        p+=1;
        if(sum>=Max) {
            Max=sum;
            if(p>MaxP) MaxP=p;
        }
        if(sum<0) sum=0,p=0;
    }
    return p;
}

3、给出一个序列,求连续子串和的最大值,长度要求大于等于2

思路:单独拿出来一个数据,保证至少每次两个数据以上,难点在于位置的更新,在小于0的时候位置更新毫无疑问,但是这个还是远远不够的,若sum(i)=sum(i-1)+a[i]<a[i],虽然和是大于0,但是sum(i-1)小于0,也需要更换位置。如测试数据,-1+8也需要移动位置。

int fun3(vector<int> a,int n){   //长度>=2
    int sum=a[0];
    int Max=-999;
    for(int i=1;i<n;i++){
        sum+=a[i];
        if(sum>Max) Max=sum;
        if(sum<0||sum<a[i]) {   //-1,8,-1,-5,10
            sum=a[i];
        }
    }
    return Max;
}

4、给出一个序列,只有0和1组成,求0和1个数相等的最长子串。

5、给出一个序列,只有-1和1组成,求和为0的最长子串。

思路:O(n)的时间复杂度,利用Map(sum,index),统计和为某个值得时候最小下标。然后后面出现相同sum时,位置做差。4和5是同一道题,把0变成-1即可。

int fun4(vector<int> a,int n){ 
    map<int,int>m;   //和,位置
    int sum=0;
    int Max=-999;
    for(int i=0;i<n;i++){
        sum+=a[i];
        if(sum==0) Max=Max>i+1?Max:i+1;
        if(m[sum]!=0){     //bug,记录坐标为0,会有冲突,map没有默认也为0
            Max=Max>(i-m[sum]+1)?Max:(i-m[sum]+1);
        }else {
            m[sum]=i+1;     //记录第一次位置
        }
    }
    return Max;
}

6、给出一个序列,求和为k的序列个数(看似背包问题,实则不是,区别:连续,不重复)

思路:上一个是求最长长度,这一个是求最大个数。都是map辅助,累和为下标记录个数或者位置,进行操作。前者是记录位置,出现相同的sum时,位置做差记录Max(注意求最长,记录第一次的即可)。后者是记录个数,当出现和为sum时,进行加一操作,代表和为sum的序列个数。若sum-k存在,那么其中的值就是和为sum-k的序列个数,那么sum和sum-k做差也就有相同的序列个数(差刚好为k),注意特殊形式,sum==k时候,sum-k肯定不存在,但是全序列刚好为k,也就是一种情况。

int fun5(vector<int> a,int n,int k){ 
    map<int,int>m;   //和,个数
    int sum=0;
    int ans=0;
    for(int i=0;i<n;i++){
        sum+=a[i];
        if(sum==k) ans+=1;
        if(m[sum-k]!=0){     //两个差为k
            ans+=m[sum-k];
        }
        m[sum]+=1;     //记录个数
    }
    return ans;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值