前缀和+二分法+滑动窗口 209. 长度最小的子数组

209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。

示例:

输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。

进阶:

如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

前缀和
求出前缀和,对每个前缀和搜索前面的,直到找到满足差值s的位置,得到其最短距离;

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n=nums.size();
        preflx.resize(n+1,0);
        int Mlength=INT_MAX;
        for(int i=1;i<=n;i++){
            preflx[i]=preflx[i-1]+nums[i-1];
            for(int j=i-1;j>=0;j--)
                if(preflx[i]-preflx[j]>=s){
                    Mlength=min(Mlength,i-j);
                    break;
                }
        }
        if(Mlength==INT_MAX) Mlength=0;
        return Mlength;
        
    }
private:
    vector<int> preflx;
};

解法2:双指针
滑动窗口;
窗口内和大于s,头指针右移,并保存距离;
窗口内和小于s,尾指针右移;

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int Minlength=INT_MAX;
        int head=0;
        int tail=0;
        int sum=0;
        int n=nums.size();
        while(tail<n)
        {
            sum+=nums[tail++];
            while(sum>=s){
                Minlength=min(tail-head,Minlength);
                sum-=nums[head++];
            }
        }
        if(Minlength==INT_MAX) Minlength=0;
        return Minlength;
    }
};

二分法
数组元素均为非负整数,故前缀和为升序序列;
故可使用二分法,在确定一个数的情况下,找到另一个数;

使用lower_bound(begin(),end(),num) 可以更方便的找到想要的数;
复杂度为二分法复杂度logn;

总复杂度为nlogn;

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n=nums.size();
        preflx.resize(n+1,0);

        int Mlength=INT_MAX;
        for(int i=1;i<=n;i++)
            preflx[i]=preflx[i-1]+nums[i-1];

        for(int i=1;i<=n;i++)
        {
            int findint=preflx[i-1]+s;
            auto t=lower_bound(preflx.begin(),preflx.end(),findint);
            if(t!=preflx.end())//找到了t
                Mlength=min(Mlength,static_cast<int>(t-(preflx.begin()+i-1)));
        }
        if(Mlength==INT_MAX) Mlength=0;
        return Mlength;
    }
private:
    vector<int> preflx;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值