双指针之滑动窗口(leetcode刷题总结)

前言

在双指针的几个题型中,最难的就是滑动窗口,其实滑动窗口的思想很简单,实现起来也不难,难点就是对于边界的处理。

一、滑动窗口算法是什么,应该怎么操作?

在滑动窗口类型的问题中都会有两个指针,一个用于「延伸」现有窗口的 r 指针,和一个用于「收缩」窗口的 ll指针。在任意时刻,只有一个指针运动,而另一个保持静止。我们在 s 上滑动窗口,通过移动 r 指针不断扩张窗口。当窗口包含 t 全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。

二、例题体验

无重复字符的最长子串
在这里插入图片描述
在这里插入图片描述

这道题目是很经典的双指针滑动窗口,对于题目的基本思路无非就是,先用一个j指针遍历数组,并且每次我们把遍历过的字符储存在数组visit标记,每次遍历的过程都判断一次,有没有出现重复字符,如果没有的话就保存最大值,如果有的话就动用i指针,把在visit数组里面的字符丢掉,到数组中不含重复字符时停止i指针,重新用j指针遍历,周而复始。

class Solution {
    int visit[256];
    bool Judge(){
        for(int i = 0;i<256;i++){
            if(visit[i]>1) return false;
        }
        return true;
    }
public:
    int lengthOfLongestSubstring(string s) {
        int i = 0,j = 0,len = 0;
        while(j<s.size()){
            visit[s[j]]++;
            if(Judge()){
                len = max(len,j-i+1);
            }else{
                while(!Judge()){
                    visit[s[i]]--;
                    i++;
                }
            }
            j++;
        }
        return len;
    }
};

同类型题目
长度最小的子数组

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int i = 0,j = 0,sum = 0,len = INT_MAX;
        while(j<nums.size()){
        	sum+=nums[j];
			if(sum>=target){
				while(sum>=target){
					len = min(len,j-i+1);
					sum-=nums[i];
					i++;
				}
			}
			j++;
		}
        return len==INT_MAX?0:len;
    }
};

字符串的排列
这个题目有个隐藏条件,就是滑动窗口的大小其实是固定的,因此同时动i,j指针即可

class Solution {
public:
int cnt[26],visit[26];
    bool Judge()
    {
        for(int i = 0;i<26;i++){
            if(cnt[i]!=visit[i]) return false;
        }
        return true;
    }
    bool checkInclusion(string s1, string s2) {
        if(s1.size()>s2.size()) return false;
        for(int i = 0;i<s1.size();i++){
            cnt[s1[i]-'a']++;
            visit[s2[i]-'a']++;
        }
        int i = 0,j = s1.size();
        while(j<s2.size()){
            if(Judge()) return true;
            visit[s2[j]-'a']++;
            visit[s2[i]-'a']--;
            i++;
            j++;
        }
        if(Judge()) return true;
        return false;
    }
};

2.较为更难的滑动窗口

最小区间
在这里插入图片描述
这个题目较比之前多了点难度,给出的数据让我们难以直接遍历查找。所以就需要先进行预处理,对每个数据都先标记为该数组的编号,然后把数据大小按顺序排序好,这样我们就可以按照上面滑动窗口的做法直接ac。

class Solution {
    int visit[3555];
    bool Judge(vector<vector<int>>& nums){
        for(int i = 0;i<nums.size();i++){
            if(!visit[i]) return false;
        }
        return true;
    }
public:
    vector<int> smallestRange(vector<vector<int>>& nums) {
        vector<pair<int,int>> v;
        vector<int> ans;
        for(int i = 0;i<nums.size();i++){
            for(int j = 0;j<nums[i].size();j++){
                v.push_back({nums[i][j],i});
            }
        } 
        sort(v.begin(),v.end());
        int i = 0,j = 0,len = 0x3f3f3f3f,l = 0,r = 0;
        while(j<v.size()){
            visit[v[j].second]++;
            while(Judge(nums)){
                if(len>v[j].first-v[i].first){
                    len = v[j].first-v[i].first;
                    l = v[i].first,r = v[j].first;
                }
                visit[v[i].second]--;
                i++;
            }
            j++;
        }
        ans.push_back(l);
        ans.push_back(r);
        return ans;
    }
};

训练题目
删除字母匹配字符

class Solution {
    bool Judge(string s1,string s2){
        int i = 0,j = 0;
        while(j<s2.size()){
            if(s1[i]==s2[j]){
                i++;
                if(i>=s1.size()) return true;
            }
            j++;
        }
        return false;
    }
public:
    string findLongestWord(string s, vector<string>& dictionary) {
        vector<string> v;
        int maxlen = 0;
        for(int i = 0;i<dictionary.size();i++){
            bool flag = Judge(dictionary[i],s);
            if(flag){
                if(maxlen<dictionary[i].size())
                    maxlen = dictionary[i].size();
                v.push_back(dictionary[i]);
            }else continue;
        }
        if(v.size()==0) return "";
        else{
            sort(v.begin(),v.end());
            for(int i = 0;i<v.size();i++){
                if(v[i].size()==maxlen){
                    return v[i]; 
                }else continue;
            }
            return v[0];
        }
    }
};

优先队列优化+滑动窗口

总结

本文总结了滑动窗口的一些用法和延伸,滑动窗口一般普通题目难度不大,思路都比较清晰,多多练习就能掌握,希望能帮助到大家。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老帅比阿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值