【完整题单01、滑动窗口】

该博客围绕滑动窗口算法展开,介绍其概念,即不断调节子序列起始和终止位置以获结果。对比暴力解法,探讨如何用一个for循环实现滑动窗口操作,指出循环索引应表示终止位置。还给出相关题单,包含LeetCode及蓝桥杯的字符串和数组滑动窗口题目,并提及思路和代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

知识框架

No.0 筑基

请先学习下知识点,道友!
题目知识点大部分来源于此:

题目例题大部分来源于此:

所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。
那么滑动窗口如何用一个for循环来完成这个操作呢?
首先要思考 如果用一个for循环,那么应该表示 滑动窗口的起始位置,还是终止位置?
如果只用一个for循环来表示 滑动窗口的起始位置,那么如何遍历剩下的终止位置?
此时难免再次陷入 暴力解法的怪圈。
所以 只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。
那么问题来了, 滑动窗口的起始位置如何移动呢?
在这里插入图片描述

No.1 字符串滑动窗口

题目来源:LeetCode-3. 无重复字符的最长子串

题目描述:

题目思路:

题目代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.size();
        map<char,int>mp;
        int ans=0;

        for(int i=0, j=0;j<len;j++){
            //先判断右边指向的是否在窗口内;
            //在里面
            if( mp[s[j] ]==1){
                while(mp[s[j]]==1){
                    mp[s[i] ]=0;
                    i++;
                }
            }
            mp[s[j] ]=1;
            ans=max(ans,j-i+1);
        }
        return ans;
    }
};



class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size() == 0) return 0;
        unordered_set<char> lookup;
        int maxStr = 0;
        int left = 0;
        for(int i = 0; i < s.size(); i++){
            while (lookup.find(s[i]) != lookup.end()){
                lookup.erase(s[left]);
                left ++;
            }
            maxStr = max(maxStr,i-left+1);
            lookup.insert(s[i]);
    }
        return maxStr;
        
    }
};

No.2 数组滑动窗口

题目来源:LeetCode-209-长度最小的子数组

题目描述:
在这里插入图片描述

题目思路:

滑动窗口的题目;

题目代码:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; // 滑动窗口数值之和
        int i = 0; // 滑动窗口起始位置
        int subLength = 0; // 滑动窗口的长度
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

题目来源:蓝桥杯-第十四届模拟-附近最小

题目描述:

在这里插入图片描述

题目思路:

题目代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e7 + 10;
int q[N];int a[N];
int b[N];int n, k;
int sum;
/*
* 滑动窗口是从寻找到的位置i开始算长度的
* 而这个是从i-k开始算的,所以题目可以转换为
* 原数组n+2k个元素,然后从1开始遍历,滑动窗口长度为2*k+1
* 记得初始化前k个元素和后k个元素极大值如1e18,这样就可以防止初值0造成影响
*/
void min_q()
{
    int h = 1, t = 0;
    int len = 2 * k + 1;
    for (int i = 1; i <= n+2*k; i++)
    {
        while (h <= t && q[h] + len <= i)h++;
        while (h <= t && b[i] < b[q[t]])t--;
        q[++t] = i;
        if (i >= len)
        {
            cout << b[q[h]] << " ";
        }
    }
    cout << endl;
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)cin >> a[i];
    cin >> k;
    for (int i = 1; i <= k; i++)b[i] = 1e18;
    for (int i = k + n + 1; i <= n + 2 * k; i++)b[i] = 1e18;
    for (int i = k + 1; i <= k + n; i++)b[i] = a[i - k];
    //for (int i = 1; i <= n + 2 * k; i++)cout << b[i] << " ";
    //cout << endl;
    min_q();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值