优选算法——滑动窗口(概念+解题模板+LeetCode例题讲解)

优选算法------滑动窗口(概念+解题模板+LeetCode例题讲解)

文章摘要: 本文系统介绍了滑动窗口算法的概念,解题模板,并通过七道经典 LeetCode 例题(长度最小的子数组、无重复字符的最长子串、最大连续1的个数、将X减到0的最小操作数、水果成篮、找出字符串中所有字母异位词、串联所有单词的子串)详细拆解其应用,从而巩固滑动窗口的知识。

目录

滑动窗口简介

1.长度最小的在子数组

2.无重复字符的最长子串

3.最大连续的个数

4.将X减到0的最小操作数

5.水果成篮

6.找出字符串中所有字母异位词

7.串联所有单词的字串

滑动窗口简介

滑动窗口(Sliding Window) 是一种基于同向双指针 的高效算法思想,常用于解决数组或字符串的连续子区间相关问题。

  • 核心思想
    将问题中的连续区间抽象为一个可以动态伸缩的"窗口",通过移动窗口的左右边界(leftright 指针),在 O(n) 时间复杂度内遍历所有可能的子区间,避免暴力枚举的 O(n²) 开销。
  • 本质
    滑动窗口的本质是同向双指针 ,通过维护窗口的合法性,减少不必要的枚举,将时间复杂度从 O(n²) 优化至 O(n)
  • 适用场景
    当你发现暴力解法需要枚举所有子区间(例如子数组、子字符串),且满足以下条件时,可考虑滑动窗口:
    *
    1. 问题涉及连续区间
      1. 可以使用同向双指针leftright 均只向右移动,不会后退)。
      1. 窗口内的状态(如元素和、字符频次等)可以高效地随指针移动而增量更新
  • 基本步骤(固定模板)
    *
    1. 初始化left = 0, right = 0,窗口为 [left, right)[left, right](根据题目定义)。
      1. 进窗口 :将 right 指向的元素加入窗口,更新窗口状态(如累加和、计数等)。
      1. 判断:检查当前窗口是否满足题目要求(如和过大、包含重复字符等)。
      1. 出窗口 :若窗口不满足条件,则移动 left 指针缩小窗口,并更新状态。
      1. 更新结果:在窗口满足条件的时机(可能在进窗口后、出窗口前或循环结束后)记录答案。
      1. 重复步骤 2‑5,直到 right 到达数组/字符串末尾。
  • 两种常见类型
    • 固定长度窗口 :窗口大小固定,每次同时移动 leftright
    • 可变长度窗口 :窗口大小根据条件动态变化,通常用于求最短/最长满足条件的子区间

正文

1.长度最小的在子数组

  • 题目链接:长度最小的子数组
  • 题目描述:

    解法一:暴力枚举
    1.定义双指针,left,right,当eft和right之间的数的和大于等于target的时候,记录结果,把所有的结果记录下来
    2.最后返回长度最小的数组的长度
    注意: 暴力枚举确实记录了所有可能的情况,但我们有必要这样做吗?题目已说明数组元素均为正整数。这意味着,一旦 leftright 之间的元素和已经大于等于 target,若此时继续向右移动 right 指针,虽然数组和会继续增大,但窗口长度也必然增加。而题目要求的是长度最小的子数组 。因此,在单趟遍历中,当窗口内元素和首次达到或超过 target 时,就可以立即停止本轮 right 的扩展,转而通过移动 left 指针来寻找更短的可行窗口。这正是滑动窗口算法的核心原理:利用数组的单调性(正整数和随窗口扩大而单调递增),避免无效的枚举,将时间复杂度从 O(n²) 优化至 O(n)。
    解法二:滑动窗口
    1.定义双指针,left,rightleft用来固定窗口左端点,right用来固定窗口的右端点
    2.数字进入窗口
    3.判断窗口内的数字之和是否大于等于target,若大于等于target,记录此时数组长度更新结果,然后出窗口。
    4.重复2.3步,直到right遍历完数组
    代码

2.无重复字符的最长子串

  • 题目链接:无重复字符的最长子串
  • 题目描述:
  • 大概思路:
    1.移动右指针,进窗口
    • right 指针指向的字符 ss[right] 加入当前窗口。
      2.判断 :检查该字符是否已存在于哈希集合中。
      • 如果不存在 :说明当前窗口 [left, right] 仍然无重复字符。将该字符加入集合,并更新结果maxLen = max(maxLen, right - left + 1)。然后 right 指针右移一位,继续尝试扩展窗口。
      • 如果存在 :说明加入该字符会导致窗口内出现重复字符,窗口不再合法。
        3.移动左指针,收缩窗口
    • 当发现 s[right] 已存在于集合中时,需要收缩窗口左侧边界,直到移除这个重复的字符。
    • left 指针指向的字符 s[left] 从哈希集合中移除,并将 left 指针右移一位。
    • 重复此步骤(移除 s[left]left++),直到集合中不再包含字符 s[right]。此时,窗口 [left, right] 重新变得合法(无重复字符)。
  1. 重复步骤 2 和 3

代码:

3.最大连续的个数

  1. 初始化left = 0, right = 0, zero = 0, maxLen = 0
  2. 进窗口right 右移,若 nums[right]0,则 zero++
  3. 判断与出窗口 :当 zero > k 时,移动 left 缩小窗口,若移出元素为 0zero--
  4. 更新结果 :每次窗口合法时 (zero <= k),更新 maxLen = max(maxLen, right - left)
  5. 循环 :重复步骤2-4,直至 right 遍历完数组,返回 maxLen
  • 代码:

4.将X减到0的最小操作数

  • 题目链接:将X减到0的最小操作数
  • 题目描述:

    问题转化:可以将问题转化为,找出最长的子数组的长度len,其中最长子数组的元素和等于sum-x(sum指数组所有元素的和),能找到sum-x这个元素和的子数组,则返回最小操作数;否则返回-1;而nums.length-len即为最小操作数
  • 大概思路(滑动窗口):
  1. 初始化left = 0, right = 0, total = 0(窗口和),target = sum - x
  2. 进窗口right 右移,total += nums[right]
  3. 判断与出窗口 :当 total > target 时,移动 left 缩小窗口,total -= nums[left]
  4. 更新结果 :当 total == target 时,更新最长子数组长度 maxLen = max(maxLen, right - left + 1)
  5. 循环 :重复步骤 2-4,直至 right 遍历完数组。最终最小操作数为 nums.length - maxLen(若 maxLen 有效)。
  • 代码:

5.水果成篮

  • 题目链接:水果成篮
  • 题目描述:
  • 大概思路(滑动窗口 + 哈希表计数):
  1. 初始化left = 0, right = 0, 哈希Map <Integer,Integer>记录窗口内水果类型及其数量,maxNum = 0
  2. 进窗口right 右移,将 fruits[right] 加入 Map。
  3. 判断与出窗口 :当 Map 中键的数量size(即水果种类)超过 2 时,移动 left 缩小窗口:将 fruits[left] 从 Map中计数减 1,若减到 0 则删除该键,left++,直到种类数 ≤ 2。
  4. 更新结果 :每次窗口合法(种类数 ≤ 2)时,更新 maxNum = max(maxNum, right - left + 1)
  5. 循环 :重复步骤 2-4,直至 right 遍历完数组,返回 `maxNum。
  • 代码:

6.找出字符串中所有字母异位词

  1. 初始化left = 0, right = 0, 两个长度为 26 的数组 hash1hash2 分别记录 p 和当前窗口的字符频次,结果列表 listcount 记录 s 中有效字符的数量。
  2. 预处理 :统计 p 的字符频次存入 hash1
  3. 进窗口right 右移,将 s[right] 加入 hash2。若 hash2 中该字符频次小于等于 hash1 中的频次,说明此次进入的是有效字符,count++
  4. 判断与出窗口 :当窗口长度 (right - left + 1) > p.length() 时,移动 left 缩小窗口:将 s[left]hash2 中移除。若移除前 hash2 中该字符频次小于等于 hash1 中的频次,说明此次删除的是有效字符,count--。然后 left++
  5. 更新结果 :当 count ==pp.length(即窗口中每种字符的数量都与 p 中完全相同)时,说明当前窗口是 p 的异位词,将 left 加入结果列表 list
  6. 循环 :重复步骤 3-5,直至 right 遍历完字符串 s,返回 list

7.串联所有单词的字串

相关推荐
Nil2081 小时前
leetcode 94二叉树的中序遍历
算法·leetcode·职场和发展
不会就选b1 小时前
算法日常・每日刷题
算法
一只小小的芙厨1 小时前
最短路总结
数据结构·算法
致Great1 小时前
OpenAI 又把 Codex 往前推了一步: 以后做 Agent,没必要都造一个聊天框
算法
aqiu1111113 小时前
【算法刷题】蓝桥杯/AtCoder:删除元素后的中位数问题(Symmetry / Median)
算法·蓝桥杯·排序·中位数
圣保罗的大教堂3 小时前
leetcode 1386. 安排电影院座位 中等
leetcode
看我眼色行事^ \/ ^3 小时前
2024.05.11 360春招WEB前端编程题
算法
一只肥瘫瘫3 小时前
编码器 PLL 角度与速度观测器原理
人工智能·算法
圣保罗的大教堂3 小时前
leetcode 3069. 将元素分配到两个数组中 I 简单
leetcode