滑动窗口算法:从零到精通,一文搞定所有套路!+ LeetCode高频考点:滑动窗口算法详解与解题模板

“面试官让我找出字符串中最长无重复子串,我用了两层循环,O(n²)的时间复杂度,面试官摇了摇头。然后他问:‘知道滑动窗口吗?’——那一刻我才明白,我与大厂offer之间,只差一个滑动窗口的距离。”

滑动窗口(Sliding Window),这个听起来有些神秘的名字,其实是解决数组/字符串子区间问题的利器。无论是字节跳动高频出现的“最小覆盖子串”,还是腾讯常考的“长度最小的子数组”,滑动窗口都能以O(n)的时间复杂度优雅解决。今天,我就带你从零开始,彻底掌握这个让算法面试变简单的核心技巧!


1. 为什么要学滑动窗口?(解决痛点)

先看一个经典问题

LeetCode 209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target
找出该数组中满足其和 ≥ target 的长度最小的连续子数组,并返回其长度。

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

暴力解法思路(最直观的想法)

  1. 枚举所有可能的子数组
  2. 计算每个子数组的和
  3. 找出满足条件的最短子数组
// 暴力解法 O(n²) int minSubArrayLen_brute(int target, vector<int>& nums) { int n = nums.size(); int minLen = INT_MAX; // 枚举所有起始位置 for (int i = 0; i < n; i++) { int sum = 0; // 枚举所有结束位置 for (int j = i; j < n; j++) { sum += nums[j]; if (sum >= target) { minLen = min(minLen, j - i + 1); break; // 找到了就break,因为后面的更长 } } } return minLen == INT_MAX ? 0 : minLen; }

暴力解法的问题分析

数组:[2, 3, 1, 2, 4, 3] 目标:sum ≥ 7 暴力解法过程: i=0: [2], [2,3], [2,3,1], [2,3,1,2] → 找到,长度=4 i=1: [3], [3,1], [3,1,2], [3,1,2,4] → 找到,长度=4 i=2: [1], [1,2], [1,2,4] → 找到,长度=3 i=3: [2], [2,4], [2,4,3] → 找到,长度=3 i=4: [4], [4,3] → 找到,长度=2 ⭐ i=5: [3] → 不满足 时间复杂度:O(n²) 当 n=10000 时,需要约 1亿 次操作

超时,严重超时了!!!

滑动窗口的优化思路

观察:窗口的连续性

假设我们有一个窗口 [2,3,1] 和为6 < 7 传统做法:丢弃整个窗口,从3重新开始 聪明做法:为什么不只丢弃左边的2,保留 [3,1] 呢? 当前窗口:[2,3,1] 和=6 < 7 扔掉左边:移除2 → [3,1] 和=4 加入右边:加入2 → [3,1,2] 和=6 加入右边:加入4 → [3,1,2,4] 和=10 ≥ 7 这样避免了重复计算 [3,1] 的和!

滑动窗口的核心思想

就像相机取景框,只移动边界,不重新拍摄整个画面

初始: [2,3,1,2,4,3] 窗口: |---| ← 和=6 < 7 left right 扩大窗口: |-----| ← 加入2,和=8 ≥ 7 收缩窗口: |-----| ← 去掉2,加入... 寻求更短的
int minSubArrayLen_sliding(int target, vector<int>& nums) { int left = 0; // 窗口左边界 int sum = 0; // 当前窗口的和 int minLen = INT_MAX; // 最小长度 int n = nums.size(); for (int right = 0; right < n; right++) { // 1. 加入右边元素(扩大窗口) sum += nums[right]; // 2. 当窗口满足条件时,尝试收缩窗口 while (sum >= target) { // 更新最小长度 minLen = min(minLen, right - left + 1); // 收缩窗口:移除左边元素 sum -= nums[left]; left++; } // 3. 如果窗口不满足条件,继续扩大窗口(下一轮循环) } return minLen == INT_MAX ? 0 : minLen; }
数组:[2, 3, 1, 2, 4, 3] 目标:sum ≥ 7 暴力解法计算过程: i=0: 2 → 5 → 6 → 8 ✔ i=1: 3 → 4 → 6 → 10 ✔ i=2: 1 → 3 → 7 ✔ i=3: 2 → 6 → 10 ✔ i=4: 4 → 7 ✔ i=5: 3 总共计算了 3+4+3+3+2+1 = 16 次加法 滑动窗口计算过程: 初始化: sum=0 right=0: sum=2 right=1: sum=5 right=2: sum=6 right=3: sum=8 (≥7) → minLen=4, sum=6, left=1 right=4: sum=10 (≥7) → minLen=3, sum=7, left=2 right=5: sum=10 (≥7) → minLen=2, sum=6, left=3 总共计算了 6 次加法 + 3 次减法 = 9 次运算

先向右扩大,当sum足够时,再从左缩小

2. 滑动窗口的核心思想

四大核心理念

1. 连续性原则

// 只处理连续的子序列,不是任意的子集 ✅ [1,2,3,4] 中的 [2,3,4] // 连续,可以用滑动窗口 ❌ [1,2,3,4] 中的 [1,3,4] // 不连续,不能用滑动窗口

2. 单调移动原则

// 左右指针只能单向移动(通常向右) int left = 0, right = 0; while (right < n) { // right只会增加 // left只会增加或不变 // 永远不会回头! }

3. 局部更新原则

// 窗口从 [2,3,1] 滑动到 [3,1,2] // 传统方法:重新计算 3+1+2 = 6 // 滑动窗口:利用已有的 2+3+1=6,然后: new_sum = old_sum - 离开的元素 + 新进入的元素 = 6 - 2 + 2 = 6 // 只计算变化的部分!

4. 最优性保证原则

// 通过合理的收缩规则,确保不会错过最优解 while (窗口不满足条件) { 收缩窗口; // 剔除"坏"元素 } // 此时窗口是当前右边界下的"局部最优"

3.leetcode题目

1.代码实现:

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

set 是 C++ STL 中的一种关联容器,它存储唯一的元素(不允许重复),并且元素会自动排序。

#include <set> #include <unordered_set> // 有序集合(基于红黑树实现) set<int> orderedSet; // 无序集合(基于哈希表实现) unordered_set<int> unorderedSet;

大致思路:

  • 用一个 unordered_set 来记录当前窗口里的字符,保证里面没有重复。
  • 双指针 left、right 表示窗口的左右边界,left 初始为 0。
  • maxLen 记录遍历过程中最长的无重复子串长度。
  • right 从左到右遍历字符串,每次尝试把 s [right] 加入窗口。
  • 如果发现 s [right] 已经在 set 里(重复了),就 不断从左边 erase 字符、left++,直到把重复的那个字符彻底移出窗口。
  • 把当前 s [right] 加入 set,更新窗口长度,维护 maxLen。
  • 遍历结束后,maxLen 就是答案。

重点讲解while循环

它的作用是:当遇到重复字符时,持续移动左指针,直到移除那个重复字符

例子:s = "abcbda"

我们用滑动窗口 [left, right] 来跟踪当前无重复字符的子串。

步骤分析:

  1. 初始状态left = 0charSet = {}
  2. right = 0'a' 不在集合中,直接加入 → charSet = {'a'}, 长度=1
  3. right = 1'b' 不在集合中,直接加入 → charSet = {'a', 'b'}, 长度=2
  4. right = 2'c' 不在集合中,直接加入 → charSet = {'a', 'b', 'c'}, 长度=3
  5. right = 3'b' 已经在集合中
    • 进入 while 循环
    • 第一次循环:移除 s[left](即 s[0] = 'a'),left = 1
    • 检查 'b' 还在集合中吗?是的,因为集合现在是 {'b', 'c'}
    • 第二次循环:移除 s[left](即 s[1] = 'b'),left = 2
    • 现在集合是 {'c'}'b' 不在集合中了
    • 退出 while 循环
    • 加入 'b',集合变为 {'c', 'b'},长度 = right - left + 1 = 3 - 2 + 1 = 2
  6. right = 4'd' 不在集合中,直接加入 → charSet = {'c', 'b', 'd'}, 长度=3

Read more

Flutter for OpenHarmony: Flutter 三方库 openid_client 深度打通鸿蒙应用的单点登录 (SSO)(基于 OpenID Connect 标准)

Flutter for OpenHarmony: Flutter 三方库 openid_client 深度打通鸿蒙应用的单点登录 (SSO)(基于 OpenID Connect 标准)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在现代企业级 OpenHarmony 应用中,为了安全和便捷,往往会使用 OpenID Connect (OIDC) 协议进行统一身份认证。无论是集成 Google 登录、GitHub 登录,还是对接企业内部的 Keycloak、Okta 等身份提供商(IdP),我们都需要一个健壮的库来处理繁杂的 OAuth2 握手流程。 openid_client 是一个功能极其全面的 Dart 实现。它能够自动发现服务器端点(Discovery)、处理 PKCE 流程并安全地交换令牌,是构建高安全级别鸿蒙应用的首选。 一、核心认证流程 OIDC 认证流程通常是通过浏览器重定向完成的,openid_client 充当了流程的指挥官。 身份服务器 (IdP)openid_client鸿蒙

By Ne0inhk
本地部署 Stable Diffusion:零基础搭建 AI文生图模型

本地部署 Stable Diffusion:零基础搭建 AI文生图模型

本地部署 Stable Diffusion:零基础搭建 AI 文生图系统 Stable Diffusion 是一款强大的开源文生图(Text-to-Image)AI 模型,可以本地运行,无需联网或付费就能生成高质量图像。相比 Midjourney、DALL·E 等云服务,Stable Diffusion 更自由、更可控。 这篇文章将手把手教你如何使用 Stable Diffusion WebUI(AUTOMATIC1111) 在本地搭建一个高效、可定制的 AI 画图系统,适合 AI 爱好者、程序员和设计师。 ✅ 目录 1. 为什么选择 Stable Diffusion? 2. 环境准备:硬件 & 软件 3. 安装与部署 WebUI 4.

By Ne0inhk

WhisperLiveKit 会议纪要模板定制:适配不同场景的纪要样式

核心定制原则 * 场景分类:区分正式会议、头脑风暴、项目复盘等场景,匹配对应的结构化模板。 * 关键元素保留:时间、参与人、决议事项、待办任务为通用必选项,其他字段按需增减。 正式会议模板示例 标题格式:[类型]项目名_日期(如[决策]Q3预算会_20240520) 内容结构: * 背景说明(3行以内) * 决议事项(编号列表,含责任人与DDL) * 争议点记录(斜体标注未达成共识项) * 附件链接(直接粘贴WhisperLiveKit生成的会议录音/转录URL) 创意讨论模板示例 标题格式:[脑暴]主题_发起人 内容结构: * 灵感池(无序列表记录所有点子) * 投票结果(用✅×3形式标记票数) * 可行性筛选(分立即执行/长期储备两栏表格) 技术评审模板示例 标题格式:[评审]系统名_

By Ne0inhk

一键部署Z-Image-Turbo:云端AI绘画不求人

一键部署Z-Image-Turbo:云端AI绘画不求人 你是不是也遇到过这样的场景:脑子里有个绝妙的画面,想把它画出来,但要么不会画画,要么打开专业绘图软件折腾半天,最后出来的效果还不如想象力的十分之一? 或者,作为内容创作者、电商运营,每天需要大量配图、海报,找图库要花钱,自己设计又太费时间,效率低得让人抓狂。 今天,我要给你介绍一个“神器”——Z-Image-Turbo 极速云端创作室。它不是一个复杂的软件,而是一个打包好的云端AI绘画应用。你不需要懂代码,不需要配置环境,甚至不需要高性能电脑,只需要点几下鼠标,就能拥有一个属于你自己的、能秒级生成高清大图的AI画室。 这听起来是不是有点不可思议?别急,跟着我,10分钟你就能亲手把它搭建起来,并画出第一张作品。 1. 为什么你需要这个“云端画室”? 在深入动手之前,我们先搞清楚,这个工具到底能帮你解决什么问题。 1.1 传统AI绘画的三大痛点 如果你之前尝试过一些AI绘画工具,可能会对这几个问题深有体会: 1. 部署复杂:想用开源的Stable Diffusion?光是安装Python、

By Ne0inhk