算法基础/滑动窗口

1.438. 找到字符串中所有字母异位词

题目描述:

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例:

示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
 

提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母

解答描述:

该题要找到s 中所有 p 的 异位词 的子串,注意:异位词 指由相同字母重排列形成的字符串(包括相同的字符串)所以只需要判断s中长度为p.size()的子串中所含元素的种类和个数和p相同即可

使用长度为p.size()的固定的滑动窗口。

首先,计算出第一个p.size()的s子串的各元素种类和数量,以及p中所有元素的种类和个数。如果相等,将起始位置压入结果。

然后,左边一个元素出窗口且左端点后移一位cnt[s[l]-'a']--,l++,右端点同步后移一位并且右边一个元素入窗口r++,cnt[s[r]-'a]++。

一直判断,直到组不成长度为n的字符串为止。

注意:由于while循环的判断条件是先用l再l++,所以可能会遗漏最后一个长度为p.size()但是满足条件的字符串,特判一下。

代码:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;

        int n1=s.size();
        int n2=p.size();
        if(n1<n2)
        {
            return ans;
        }

        vector<int> cnt1(26,0);//用vector判相等时可以直接==
        vector<int> cnt2(26,0);

        //先算出p中每个字符出现的次数
        for(int i=0;i<n2;i++)
        {
            cnt2[p[i]-'a']++;
            cnt1[s[i]-'a']++;
        }

        //滑动窗口,大小为n2
        int l=0;
        int r=n2-1;
       
        while(l<n1-n2)//注意这里的n1-n2 超过这个范围不可能满足题意
        {
            if(cnt1==cnt2)
            {
                ans.push_back(l);
            }
            cnt1[s[l]-'a']--;//左边一个元素出窗口
            l++;
            r++;
            cnt1[s[r]-'a']++;//右边一个元素进窗口  
        }
        if(cnt1==cnt2)//最后一组也满足条件 压入
        {
            ans.push_back(l);
        }
        return ans;
    }
};

2.713. 乘积小于K的子数组

题目描述:

给定一个正整数数组 nums和整数 k 。

请找出该数组内乘积小于 k 的连续的子数组的个数。

示例:

示例 1:
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。
示例 2:

输入: nums = [1,2,3], k = 0
输出: 0
 

提示: 
1 <= nums.length <= 3 * 104
1 <= nums[i] <= 1000
0 <= k <= 106

解答描述:

该题要找出该数组内乘积小于 k 的连续的子数组的个数。采用窗口不固定的滑动窗口

首先,令窗口的左右端点都为0,然后对每一个右端点,找到以右端点为结束的最大的满意的条件的长度,寻找的方式是从左端点开始一直连乘,扩展右端点,直到乘积>=k时,移除滑动窗口左端的元素,对于每一个r,【l,r】内的元素都是满足题意的,共有连续子数组个数r-l+1。

代码:

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        int ans=0;
        int n=nums.size();
        if(k==0 || k==1)//nums数组元素为正整数
        {
            return ans;
        }
        //使用窗口大小不固定的滑动窗口
        int mul=1;//当前相乘的结果
        int l=0;
        for(int r=0;r<n;r++)//计算以每个右边界的<k的连续子数组个数
        {
            mul*=nums[r];//一直乘下去可能会溢出 
            while(mul>=k)//当mul大于等于k时,考虑窗口左端要移除元素
            {
                mul/=nums[l];
                l++;
            }
            //滑动窗口内的元素的乘积都不会超过K,且因为要连续,所以组合方式等于元素长度r-l+1种
            ans += r - l + 1;

        }
        return ans;
    }
};

3.209. 长度最小的子数组

题目描述:

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例:

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

示例 2:
输入:target = 4, nums = [1,4,4]
输出:1

示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

解答描述:

和上一题连乘非常相似,都是窗口大小不固定的滑动窗口

但是要注意的是,上一题是要找到所有满足条件的,所以是在不满足条件的时候进行窗口移动

而这一题是要找到满足条件的最小长度的,所以要在满足条件的时候移动以求更优的解。

注意:可能会出现遍历完所有的数加起来都没有target大的情况,这种时候需要返回0.

代码:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        int min_len=INT_MAX;
        int sum=0;
        //滑动窗口找到每个l开始的大于等于target的最小长度
        int l=0;
        int r=0;
      
        while(r<n)
        {
            sum+=nums[r];
            while(sum>=target)
            { 
                min_len=min(min_len,r-l+1);
                sum-=nums[l++];  
            }     
            r++;
        }
        return min_len==INT_MAX?0:min_len;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值