【算法拾光】滑动窗口|长度最小的子数组 + 无重复字符的最长子串

前言

滑动窗口本质上是双指针的一种特殊形式,两个指针left、right划定一个窗口区间,通过不断移动右指针扩大窗口,满足 / 不满足条件时移动左指针收缩窗口,避免暴力枚举所有子区间,把 O (n²) 复杂度优化到 O (n)。

滑动窗口分两大类:

  1. 固定窗口:窗口大小不变;
  2. 可变窗口(动态窗口):窗口大小随条件伸缩,本篇两道都是可变窗口,也是面试高频题型。
  • 长度最小的子数组:满足条件找最小窗口
  • 无重复字符的最长子串:满足条件找最大窗口

题目一:长度最小的子数组209. 长度最小的子数组 - 力扣(LeetCode)

题目描述

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

示例:

cpp 复制代码
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是满足条件的最小长度子数组。

思路分析

暴力思路:枚举所有起始位置,不断累加,找到满足和≥target 的子数组,时间复杂度 O (n²),数组长度大时会超时。

滑动窗口思路(可变窗口,求最小窗口):

  1. 定义左右指针left = 0,窗口内总和sum = 0;
  2. right指针不断向右移动,把nums[right]加入窗口总和;
  3. 当窗口总和 ≥ target ,说明当前窗口满足条件:
    • 更新最小窗口长度;
    • 尝试收缩左边界:sum -= nums[left],left++,继续判断窗口是否依然满足条件,持续缩小窗口寻找更优解;
  4. 遍历结束,返回最小长度。

关键点:数组全部是正数,窗口右扩总和变大,左缩总和变小,单调性保证滑动窗口可行。

C++ 代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int minSubArrayLen(int target, vector<int>& nums) {
    int left = 0;
    int sum = 0;
    int res = INT_MAX;
    for (int right = 0; right < nums.size(); right++) {
        sum += nums[right];
        // 满足条件,收缩左边界
        while (sum >= target) {
            res = min(res, right - left + 1);
            sum -= nums[left];
            left++;
        }
    }
    return res == INT_MAX ? 0 : res;
}

int main() {
    vector<int> nums = {2,3,1,2,4,3};
    cout << minSubArrayLen(7, nums) << endl;
    return 0;
}

复杂度分析

  • 时间复杂度:O (n),left和right最多各遍历数组一次。
  • 空间复杂度:O (1),仅使用常数变量。

题目二:无重复字符的最长子串3. 无重复字符的最长子串 - 力扣(LeetCode)

题目描述

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

示例:

cpp 复制代码
输入: s = "abcabcbb"
输出: 3
解释: 无重复字符的最长子串是 "abc",其长度为 3。

思路分析

暴力思路:枚举所有子串,用集合判断是否有重复字符,O (n²),效率低。

滑动窗口思路(可变窗口,求最大窗口):

  1. left = 0,右指针right不断向右扩大窗口;
  2. 使用哈希集合(或数组)保存当前窗口内的字符;
  3. 如果s[right]已经在窗口中:
    • 不断移除窗口最左侧字符s[left],left++,直到窗口内不存在重复字符;
  4. 窗口合法后,记录窗口长度,更新最大值;

对比上一题: 长度最小子数组:满足条件就收缩左边界,尽可能缩小窗口 无重复最长子串:出现重复才收缩左边界,尽可能扩大窗口

C++ 代码

cpp 复制代码
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;

int lengthOfLongestSubstring(string s) {
    unordered_set<char> win;
    int left = 0;
    int maxLen = 0;
    for (int right = 0; right < s.size(); right++) {
        // 存在重复字符,收缩左边界
        while (win.count(s[right])) {
            win.erase(s[left]);
            left++;
        }
        win.insert(s[right]);
        maxLen = max(maxLen, right - left + 1);
    }
    return maxLen;
}

int main() {
    string s = "abcabcbb";
    cout << lengthOfLongestSubstring(s) << endl;
    return 0;
}

复杂度分析

  • 时间复杂度:O (n),左右指针最多遍历字符串一次;字符的插入删除是 O (1)。
  • 空间复杂度:O (Σ),Σ 是字符集大小,最多存放所有不重复字符。

优化小技巧:如果限定是 ASCII 字符,可以用大小 128 的数组代替 unordered_set,速度更快。

cpp 复制代码
// 数组版本
int lengthOfLongestSubstring(string s) {
    int hash[128] = {0};
    int left = 0, maxLen = 0;
    for(int right = 0; right < s.size(); right++){
        while(hash[s[right]] != 0){
            hash[s[left]]--;
            left++;
        }
        hash[s[right]]++;
        maxLen = max(maxLen, right-left+1);
    }
    return maxLen;
}

两道题核心对比总结

表格

题目 窗口目标 收缩时机 特点
长度最小的子数组 求满足条件的最小窗口 窗口满足条件时,持续收缩左边界 数组全正数,和具备单调性
无重复字符的最长子串 求满足条件的最大窗口 窗口出现非法元素(重复字符)才收缩 维护窗口内元素唯一性

滑动窗口通用模板记忆:

cpp 复制代码
left = 0
for right 遍历数组/字符串:
    将right元素加入窗口
    while 窗口不合法(或窗口满足条件):
        更新答案
        移除left元素,left++
    更新答案

核心难点:判断 while 循环条件,以及什么时候更新结果。 ✅ 求最小窗口:while 满足条件,收缩,更新结果 ✅ 求最大窗口:while 不满足条件,收缩,更新结果

结尾

滑动窗口是数组、字符串面试的高频考点。两道题一个求最小窗口、一个求最大窗口,刚好覆盖可变滑动窗口两大经典场景。掌握两者的区别,遇到子数组、子串问题,可以优先思考是否能用滑动窗口优化暴力解法。

相关推荐
weixin_307779131 小时前
C++代码实现MATLAB中的fitnlm函数功能
开发语言·c++·算法·matlab
雪落漂泊1 小时前
C++算法:双指针篇(下)
数据结构·c++·算法
生态学者11 小时前
Global Change Biology | 森林越“步调一致”,反而越怕干旱?树木生长与叶片活动的同步之谜
大数据·人工智能·算法·r语言·微信公众平台
lsswear11 小时前
Agent 框架新手入门与实战部署指南
大数据·人工智能·算法
Data analyse45613 小时前
rnweb 回放数据量太大怎么办?分片存储与断点续传的实现思路
前端·网络·算法·数据分析
Navigator_Z14 小时前
LeetCode //C - 1293. Shortest Path in a Grid with Obstacles Elimination
c语言·算法·leetcode
Nil20815 小时前
leetcode 64最小路径和
算法·leetcode·职场和发展
光影少年15 小时前
AI Agent、自动化与未来工作
人工智能·算法·架构
牧羊人.33315 小时前
计算机视觉基础 第16章|EigenFace,FisherFace,LBPH传统人脸识别算法
人工智能·算法·计算机视觉