必学算法——滑动窗口

零、前言:

众所周知,滑动窗口算法是算法学习中必须要掌握的算法之一,在蓝桥杯,acm,力扣等编程竞赛的题目中会出现,该算法还不算很难搞懂,是基础算法之一,所以我们要打好基础,下面让我们来学习滑动窗口。

在这里插入图片描述

一、滑动窗口的应用场景

滑动窗口算法 (Sliding Window)是一种常用的双指针算法,被广泛应用于字符串和数组等数据结构中的子串或子数组问题,例如字符串匹配、最长子串、最小覆盖子串等问题。 滑动窗口算法可以优化暴力枚举的时间复杂度,使得算法的执行效率更高。

二、滑动窗口的动态图

在这里插入图片描述

三、时间复杂度分析:

时间复杂度分析: 暴力解法的时间复杂度一般为O(N ^ 3):O(N ^ 2)枚举所有的子串,O(N)判断是否满足条件。
滑动窗口在两个方面都降低时间复杂度:首先并不枚举所有的子串,只枚举可能包含答案的那些。其次通过记录窗口内子串的一些信息,使得判断是否满足条件的时间复杂度下降。

四、经典例题

1、蓝桥杯经典真题——挑选子串
(帅哥们蓝色字体点进去可以看题目)

1.0、思路分析

这是一个很巧妙地思想将输入的数组所有数组元素大于等于m(a[i]>=m)变为1,反之为0,也就是我们在遍历数组该元素满足条件则子串计数器加1,让j先往后跑,若是字符串中满足条件元素的个数为k时就j让就停下,此时j往后的数组元素添加到该子字符串都满足所以将结果值ans+=j-i+1,i往后跑继续判断该子字符串是否满足,直到i,j都遍历完数组就结束。

1.1、代码分析

#include <iostream>
using namespace std;

int a[2001];

int slideWindow(int n,int k,int*a){
    int i=0,j=-1,sum=0;
    int ans=0;
    while(j++<n){
        sum+=a[j];
        while(sum>=k){
            ans+=n-j;
            sum-=a[i];//i++以后将原来i在的位置的元素的值从计数器sum中减去
            i++;
        }
    }
    return ans;
}

int main()
{   
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=0;i<n;i++){
        cin>>a[i];
        a[i]=(a[i]>=m?1:0);//将数组中所有大于m的值变成1,反之为0
    }
    int ans=slideWindow(n,k,a);
    cout<<ans<<endl;
    return 0;
}

2、蓝桥杯经典真题——最长子串

2.0、思路分析

这题与第一题思路基本一样,就是用一个数组来记录每个元素(即s[i])的个数,表示方法为count[s[i]],其余的步骤都一样,换汤不换药。

2.1、代码分析

#include <iostream>
#include<string>
using namespace std;

int slideWindow(int n,int k,const string& s){
    int i=0,j=-1;
    int ans=0;
    int count[256]={0};
    while(j++<n-1){
        count[s[j]]++;
        while(count[s[j]]>k){
            count[s[i]]--;//s[i]就是i++之前那个元素,这个元素要删除,所以要减1
            i++;
        }
        int ret=j-i+1;
        ans=max(ans,ret);
    }
    return ans;
}

int main()
{
    string s;
    int k;
    cin>>s>>k;
    int ans=slideWindow(s.size(),k,s);
    cout<<ans<<endl;
    return 0;
}

3、蓝桥杯经典真题——全部都有的子序列

3.0、思路分析

这题与第一,二题思路也基本一样,就不过多解释了,相信你们理解前面两道题这道肯定手拿把掐。

3.1、代码分析

#include <iostream>
#include<cstring>
using namespace std;

int a[100001];

int slideWindow(int n,int*a){
    int i=0,j=-1;
    int cnt[1001]={0};
    int need=0,sum=0,ret=n;//因为要找最短长度,所以把ret赋值最大长度n
    for(int i=0;i<n;i++){
        cnt[a[i]]++;
        if(cnt[a[i]]==1)need++;//计算出所有不同元素的个数
    }
    memset(cnt,0,sizeof(cnt));//把计数数组全变回去,赋值为0
    while(j++<n-1){
        cnt[a[j]]++;
        if(cnt[a[j]]==1)sum++;
        while(sum==need){
            ret=min(ret,j-i+1);
            cnt[a[i]]--;
            if(!cnt[a[i]])sum--;
            i++;
        }
    }
    return ret;
}

int main()
{
  int n;
  cin>>n;
  for(int i=0;i<n;i++)cin>>a[i];
  int ans=slideWindow(n,a);
  cout<<ans<<endl;
  return 0;
}

希望各位帅哥可以点赞,关注支持一下,非常感谢!!!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值