跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

滑动窗口算法入门:经典例题实战解析

滑动窗口算法常用于处理数组或字符串的连续子序列问题。通过维护左右指针动态调整区间范围,可高效解决寻找满足特定条件的最小子数组、最长无重复子串等问题。结合四道经典例题,详细讲解双指针移动逻辑、哈希表配合技巧及状态转换思路,帮助读者掌握 O(n) 时间复杂度的解题核心。

蜜桃汽水发布于 2026/3/23更新于 2026/10/2688 浏览
滑动窗口算法入门:经典例题实战解析

简要介绍

滑动窗口算法在笔试面试以及算法竞赛中非常常见,主要用于处理数组和字符串问题,特别适合寻找满足某个条件的子数组或子字符串,或者用于连续子问题的计算。

顾名思义,'滑动窗口'就是维护一个区间,这个窗口的大小可以是固定的也可以是变化的。它会在数据结构上移动来扫描数据。基本套路通常包括四个步骤:

  1. 进窗口:右指针移动,将新元素加入当前窗口。
  2. 判断条件:根据题意分析当前窗口是否满足要求。
  3. 更新结果:如果满足条件,记录或更新最优解。
  4. 出窗口:左指针移动,移除旧元素,缩小窗口以尝试更优解。

相关例题

长度最小的子数组

题目描述

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

示例:

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

这是一个典型的滑动窗口题目。暴力解法需要遍历数组两次,时间复杂度为 $O(n^2)$。考虑到数据规模可能达到 $10^5$,暴力解会超时。虽然可以使用前缀和加二分查找优化到 $O(n \log n)$,但滑动窗口可以将复杂度进一步降低到 $O(n)$。

实现思路

我们需要维护一个滑动窗口,窗口内的值之和小于目标值时继续扩张,一旦大于等于目标值就收缩左边界以寻找最小长度。具体过程如下:

定义两个指针,分别指向窗口的开头和结尾,同时初始化一个变量记录最大长度。接着开始维护窗口:首先将右指针当前指向的值加入窗口;然后判断窗口和是否大于等于目标值,如果是则更新结果并将左指针指向的值移出窗口(实现向右滑动);最后右指针右移一位。

实现代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size(), sum = 0, len = INT_MAX;
        for (int left = 0, right = 0; right < n; right++) {
            sum += nums[right]; 
             (sum >= target) {
                len = (len, right - left + ); 
                sum -= nums[left++]; 
            }
        }
         len == INT_MAX ?  : len;
    }
};
// 进窗口
while
min
1
// 更新结果
// 出窗口
return
0

无重复字符的最长子串

题目描述

给定一个字符串 s,请你找出其中不含有重复字符的 最长 子串 的长度。

示例:

输入:s = "abcabcbb"
输出:3
解释:因为无重复字符的最长子串是 "abc",所以其长度为 3。
题目分析

题目要求找特征字串,适合用滑动窗口解决。约束条件在于窗口内不能有重复字符。这与之前的题目类似,只是判断条件变成了字符计数。

实现思路

使用哈希表记录字符出现的次数。移动右指针,将字符加入窗口并增加计数。如果发现当前字符计数大于 1,说明有重复,此时移动左指针直到窗口内无重复字符。每次移动后更新最大长度。

实现代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> hash;
        int n = s.size();
        int len = -1;
        for (int i = 0, j = 0; j < n;) {
            hash[s[j]]++; // 进窗口
            while (hash[s[j]] > 1) {
                hash[s[i++]]--; // 出窗口
            }
            len = max(len, j - i + 1);
            j++;
        }
        return len == -1 ? 0 : len;
    }
};

最大连续 1 的个数 III

题目描述

给定一个二进制数组 nums 和一个整数 k,假设最多可以翻转 k 个 0,则返回执行操作后 数组中连续 1 的最大个数。

题目分析

换个思路理解,这个问题等价于求一个最长区间,使得区间内 0 的个数不超过 k 个。既然数字只有 0 和 1,这就变成了求某特征区间的问题,可以直接套用滑动窗口模板。

实现思路

定义两个指针指向最左端,设置计数器记录窗口内 0 的数量。循环中,若当前值为 0 则计数加一。如果 0 的数量超过 k,则将左指针右移并减少计数,直到满足条件。最后更新最终答案。

实现代码
class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n = nums.size();
        int cnt = 0;
        int ret = -1;
        for (int i = 0, j = 0; j < n; j++) {
            if (nums[j] == 0) {
                cnt++;
            }
            while (cnt > k) {
                if (nums[i++] == 0) {
                    cnt--;
                }
            }
            ret = max(ret, j - i + 1);
        }
        return ret == -1 ? 0 : ret;
    }
};

将 x 减到 0 的最小操作数

题目描述

给你一个整数数组 nums 和一个整数 x。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。如果可以将 x 恰好 减到 0,返回 最小操作数;否则,返回 -1。

题目分析

这道题具有迷惑性。我们可以将其转化一下:其实它问的是求一个最长的区间,区间里面的值等于原来数组的和减去 x。这样我们就变成了求最长区间的和等于目标值,依然可以使用滑动窗口来实现。

实现思路

第一步计算数组总和减去 x 得到目标值,如果小于 0 直接返回 -1。定义两个指针指向最左端,进入循环后将右指针的值加入窗口。如果窗口和大于目标值,将左指针指向的值移出窗口。跳出循环后更新结果。最后返回数组长度减去找到的最长子数组长度。

实现代码
class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int n = nums.size();
        int k = 0;
        for (auto s : nums) {
            k += s;
        }
        k -= x;
        if (k < 0) return -1;
        
        int len = -1;
        int sum = 0;
        for (int i = 0, j = 0; j < n; j++) {
            sum += nums[j]; // 进窗口
            while (sum > k) {
                sum -= nums[i++]; // 出窗口
            }
            if (sum == k) {
                len = max(len, j - i + 1);
            }
        }
        return len == -1 ? -1 : n - len;
    }
};

目录

  1. 简要介绍
  2. 相关例题
  3. 长度最小的子数组
  4. 题目描述
  5. 题目分析
  6. 实现思路
  7. 实现代码
  8. 无重复字符的最长子串
  9. 题目描述
  10. 题目分析
  11. 实现思路
  12. 实现代码
  13. 最大连续 1 的个数 III
  14. 题目描述
  15. 题目分析
  16. 实现思路
  17. 实现代码
  18. 将 x 减到 0 的最小操作数
  19. 题目描述
  20. 题目分析
  21. 实现思路
  22. 实现代码

更多推荐文章

查看全部
  • IDEA 中 Java 及 Java Web 项目常见问题
  • GLM-5 全栈实战:从本地部署到多 Agent 架构应用
  • 为什么顶级团队开始重押 Harness Engineering?AI Agent 时代的底层答案来了
  • Linux 动静态库原理及编译链接实战
  • Whisper-Large-V3-Turbo 模型高效部署实战
  • 电商产品 AI 绘画提示词高效撰写指南
  • Pi0 机器人 VLA 大模型昇腾 A2 平台测评
  • VSCode Copilot 接入 OpenAI 兼容自定义模型方案
  • 声源定位算法基础:常规波束形成(CBF)原理
  • 线性 DP 经典四题详解:台阶、子段和、传球与乌龟棋
  • PyTorch 实战:StyleGAN 模型详解与风格迁移实现
  • 基于 Spring Boot 的学生成绩管理系统设计与实现
  • MCP Server 实现 Excel 表格一键生成可视化图表 HTML 报告
  • 前端跨子域通讯实战:核心方案与避坑指南
  • Qwen3-VL WebUI 部署稳定性测试:72 小时压测实录
  • Stable Diffusion 本地部署与 WebUI 安装详解
  • 知网 AIGC 检测原理与论文降重实操指南
  • 实战篇:Python 开发 MongoDB 数据库 MCP Server
  • 机器人脑部药物递送三大技术路径的可转化性分析
  • iOS 设备运行 Minecraft Java 版配置与使用指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online