当前位置: 首页 > article >正文

【每日算法】Day 12-1:滑动窗口算法精讲——子串/子数组问题的优化利器(C++实现)

攻克子串问题的效率密码!今日深入解析滑动窗口算法的核心思想与实战技巧,覆盖最小覆盖子串、最长无重复子串等高频场景,彻底掌握O(n)时间复杂度的窗口滑动艺术。


一、滑动窗口核心思想

滑动窗口(Sliding Window) 是一种通过维护动态窗口解决子串/子数组问题的算法,核心特性:

  1. 双指针驱动:左指针收缩窗口,右指针扩展窗口

  2. 窗口单调性:窗口滑动过程保持单向性

  3. 哈希表辅助:快速统计窗口内元素状态

适用场景:

  • 连续子数组/子串的最值问题

  • 统计满足特定条件的区间数量

  • 字符串匹配与模式查找

与暴力解法的对比优势:

方法时间复杂度空间复杂度适用数据规模
暴力枚举O(n²)O(1)n < 10³
滑动窗口O(n)O(k)n ≤ 10⁶

二、滑动窗口模板(C++)

通用模板结构
void slidingWindow(string s) {unordered_map<char, int> window; // 窗口状态记录int left = 0, right = 0;         // 双指针while (right < s.size()) {char c = s[right];right++;                    // 右扩窗口window[c]++;                // 更新状态while (窗口需要收缩条件) {   // 左缩窗口char d = s[left];left++;window[d]--;            // 更新状态}// 更新全局结果(位置取决于具体问题)}
}
关键参数:
  • 窗口状态记录:哈希表/数组记录字符频率

  • 收缩条件:触发窗口调整的阈值条件

  • 结果更新时机:根据问题需求在适当位置更新结果


三、四大高频应用场景

场景1:最小覆盖子串(LeetCode 76)
string minWindow(string s, string t) {unordered_map<char, int> need, window;for (char c : t) need[c]++;int left = 0, right = 0;int valid = 0; // 匹配字符数int start = 0, len = INT_MAX;while (right < s.size()) {char c = s[right++];if (need.count(c)) {window[c]++;if (window[c] == need[c]) valid++;}while (valid == need.size()) { // 满足条件时收缩if (right - left < len) {  // 更新最小窗口start = left;len = right - left;}char d = s[left++];if (need.count(d)) {if (window[d] == need[d]) valid--;window[d]--;}}}return len == INT_MAX ? "" : s.substr(start, len);
}
场景2:最长无重复子串(LeetCode 3)
int lengthOfLongestSubstring(string s) {unordered_map<char, int> window;int left = 0, right = 0, max_len = 0;while (right < s.size()) {char c = s[right++];window[c]++;while (window[c] > 1) { // 出现重复char d = s[left++];window[d]--;}max_len = max(max_len, right - left);}return max_len;
}
场景3:长度最小的子数组(LeetCode 209)
int minSubArrayLen(int target, vector<int>& nums) {int left = 0, sum = 0, min_len = INT_MAX;for (int right = 0; right < nums.size(); ++right) {sum += nums[right];while (sum >= target) { // 满足条件时收缩min_len = min(min_len, right - left + 1);sum -= nums[left++];}}return min_len == INT_MAX ? 0 : min_len;
}
场景4:字符串排列(LeetCode 567)
bool checkInclusion(string s1, string s2) {unordered_map<char, int> need, window;for (char c : s1) need[c]++;int left = 0, right = 0, valid = 0;while (right < s2.size()) {char c = s2[right++];if (need.count(c)) {window[c]++;if (window[c] == need[c]) valid++;}while (right - left >= s1.size()) { // 窗口大小固定if (valid == need.size()) return true;char d = s2[left++];if (need.count(d)) {if (window[d] == need[d]) valid--;window[d]--;}}}return false;
}

四、滑动窗口变种与优化

变种类型特点经典问题
固定窗口窗口大小固定字符串排列、滑动窗口平均值
可变窗口窗口大小动态变化最小覆盖子串、最长子串
哈希表优化用数组替代哈希表加速ASCII字符集问题
前缀和+窗口结合前缀和数组处理子数组和和等于k的最长子数组

五、大厂真题实战

真题1:最大连续1的个数 III(某大厂2024面试)

题目描述:
二进制数组最多翻转k个0为1,求最长连续1子数组
滑动窗口解法:

int longestOnes(vector<int>& nums, int k) {int left = 0, max_len = 0, zero_count = 0;for (int right = 0; right < nums.size(); ++right) {if (nums[right] == 0) zero_count++;while (zero_count > k) { // 窗口内0超过k个if (nums[left] == 0) zero_count--;left++;}max_len = max(max_len, right - left + 1);}return max_len;
}
真题2:替换后的最长重复字符(LeetCode 424)
int characterReplacement(string s, int k) {vector<int> count(26, 0);int left = 0, max_count = 0, max_len = 0;for (int right = 0; right < s.size(); ++right) {count[s[right]-'A']++;max_count = max(max_count, count[s[right]-'A']);while (right - left + 1 - max_count > k) { // 需要替换超过k次count[s[left]-'A']--;left++;}max_len = max(max_len, right - left + 1);}return max_len;
}

六、复杂度与优化策略

操作时间复杂度空间复杂度优化技巧
窗口滑动O(n)O(1)数组替代哈希表
状态更新O(1)O(k)位运算压缩状态
收缩检测O(1)O(1)记录最大值避免全扫描

七、常见误区与调试技巧

  1. 窗口收缩条件错误:未正确维护窗口有效性(如LeetCode 424中的替换次数计算)

  2. 哈希表更新遗漏:左指针移动时未同步更新状态

  3. 初始化错误:未正确初始化哈希表或计数器

  4. 调试技巧

    • 打印窗口左右边界及内部状态

    • 可视化窗口滑动过程

    • 添加断言检查窗口有效性


LeetCode真题训练:

  • 438. 找到字符串中所有字母异位词

  • 567. 字符串的排列

  • 1004. 最大连续1的个数 III

相关文章:

【每日算法】Day 12-1:滑动窗口算法精讲——子串/子数组问题的优化利器(C++实现)

攻克子串问题的效率密码&#xff01;今日深入解析滑动窗口算法的核心思想与实战技巧&#xff0c;覆盖最小覆盖子串、最长无重复子串等高频场景&#xff0c;彻底掌握O(n)时间复杂度的窗口滑动艺术。 一、滑动窗口核心思想 滑动窗口&#xff08;Sliding Window&#xff09; 是一…...

树莓派超全系列文档--(7)RaspberryOS播放音频和视频

播放音频和视频 播放音频和视频VLC 媒体播放器vlc GUIvlc CLI使用 cvlc 在没有图形用户界面的情况下播放媒体 在 Raspberry Pi OS Lite 上播放音频和视频指定音频输出设备指定视频输出设备同时指定音频和视频输出设备提高数据流播放性能 文章来源&#xff1a; http://raspberr…...

chrome浏览器下载和Chrome浏览器的跨域设置

Chrome浏览器的跨域设置 下载chrome浏览器设置chrome跨域 下载chrome浏览器 点击官方下载&#xff0c;然后逐步安装即可 设置chrome跨域 1、然后在D盘创建个文件夹命名为ChromeDevSession。 2、右击chrome浏览器选择属性。 3、在目标编辑栏的最后加上&#xff1a;–disabl…...

Android14 SystemUI中添加第三方AIDL

由于特殊需求&#xff0c;需要在SystemUI中添加第三方AIDL&#xff0c;去做一些客制化的修改。现在记录一下AIDL添加的过程。 1.将AIDL文件拷贝到frameworks/base/packages/SystemUI/src/下&#xff0c;我要添加的AIDL文件是com/test/myctr/IDevicectr.aidl&#xff0c;添加后的…...

Appium中元素定位之一组元素定位API

应用场景 和定位一个元素相同&#xff0c;但如果想要批量的获取某个相同特征的元素&#xff0c;使用定位一组元素的方式更加方便 在 Appium 中定位一组元素的 API 与定位单个元素的 API 类似&#xff0c;但它们返回的是一个元素列表&#xff08;List<MobileElement>&am…...

【高并发内存池】第六弹---深入理解内存管理机制:ThreadCache、CentralCache与PageCache的回收奥秘

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】【项目详解】 目录 1、threadcache回收内存 2、centralcache回收内存 3、pagecache回收内存 1、threadcache回收内…...

累积分布策略思路

一种基于概率密度和累积分布函数的量化交易策略&#xff0c;主要应用于期货市场。该策略通过计算价格数据的概率密度和累积分布函数&#xff08;CDF&#xff09;&#xff0c;结合移动平均线和ATR&#xff08;平均真实范围&#xff09;等技术指标&#xff0c;实现多空交易的自动…...

【JavaScript】九、JS基础练习

文章目录 1、练习&#xff1a;对象数组的遍历2、练习&#xff1a;猜数字3、练习&#xff1a;生成随机颜色 1、练习&#xff1a;对象数组的遍历 需求&#xff1a;定义多个对象&#xff0c;存数组&#xff0c;遍历数据渲染生成表格 let students [{ name: 小明, age: 18, gend…...

RAG、大模型与智能体的关系

一句话总结&#xff1a; RAG&#xff08;中文为检索增强生成&#xff09; 检索技术 LLM 提示。 RAG、大模型与智能体的关系解析 1. 核心概念定义 RAG&#xff08;检索增强生成&#xff09; 是一种结合信息检索与生成式模型的框架&#xff0c;通过从外部知识库&#xff08;如…...

使用firewall-cmd配置SIP端口转发,实现双网卡互通,内外网方式

使用firewall-cmd配置SIP端口转发,实现双网卡,内外网方式 脚本内容 这里以内网IP: 192.168.2.88 这里以外网IP: 10.3.3.3 以下是一个用于启用和停用端口转发的Shell脚本&#xff1a; #!/bin/bash# 配置变量 ZONE"public" TARGET_IP"192.168.2.88" POR…...

Oracle数据库数据编程SQL<3.2 PL/SQL 匿名块中的DML操作、动态SQL、实际应用场景、使用技巧>

匿名块是学习和测试PL/SQL代码的强大工具&#xff0c;特别适合执行一次性任务或快速验证业务逻辑。 目录 一、匿名块中的DML操作 1. INSERT 示例 2. UPDATE 示例 3. DELETE 示例 二、匿名块中的动态SQL 1. EXECUTE IMMEDIATE 2. 动态游标--下篇文章会具体展开详细分享该…...

Spring AI Alibaba 实战:集成 OpenManus 实现智能体应用开发

引言 2024 年 9 月&#xff0c;阿里云正式开源 Spring AI Alibaba&#xff0c;为 Java 开发者提供了一套完整的 AI 应用开发框架&#xff0c;支持与通义系列大模型深度集成&#xff0c;并覆盖了从模型调用到云原生部署的全链路能力。而近期&#xff0c;中国团队发布的通用型 A…...

Linux中《进程状态--进程调度--进程切换》详细介绍

目录 进程状态Linux内核源代码怎么说运行&&阻塞&&挂起内核链表 进程状态查看Z(zombie)-僵尸进程僵尸进程危害孤儿进程 进程优先级进程切换Linux2.6内核进程O(1)调度队列 进程状态 Linux内核源代码怎么说 为了弄明白正在运⾏的进程是什么意思&#xff0c;我们…...

Element PlusAnt-design常问问题详解

Element UI Plus 高频面试问题解析(2025 版) 一、核心组件使用与原理 动态表头实现方案 • 场景:如何根据接口数据动态生成表头? • 技术方案: ◦ 使用 v-for 遍历表头数组生成 el-table-column ◦ 结合 render-header 属性实现复杂表头(如带提示的标题) ◦ 示例代码:通…...

【商城实战(96)】打造商城监控利器Prometheus与Grafana

【商城实战】专栏重磅来袭&#xff01;这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建&#xff0c;运用 uniapp、Element Plus、SpringBoot 搭建商城框架&#xff0c;到用户、商品、订单等核心模块开发&#xff0c;再到性能优化、安全加固、多端适配&#xf…...

Megatron-LM中的deepseek-v3实现

Megatron-LM&#xff1a;https://github.com/NVIDIA/Megatron-LM/tree/main 使用此仓库构建的著名的库也有很多&#xff0c;如: Colossal-AI, HuggingFace Accelerate, and NVIDIA NeMo Framework.Pai-Megatron-Patch工具是阿里人工智能平台PAI算法团队研发,ai-Megatron-Patch…...

SpringCloud如何整合DeepSeek

SpringCloud 整合 DeepSeek 的核心目标是通过微服务架构调用其分布式文件系统&#xff08;如 3FS&#xff09;或 API 服务。以下从技术选型、整合步骤和关键配置三个方面展开说明&#xff1a; 一、技术选型与架构分析 DeepSeek 服务类型 3FS 分布式文件系统&#xff1a;基于 RD…...

蓝桥杯备考:多米诺骨牌

这道题要求上下方格子和之差要最小&#xff0c;其实就是算每个上下格子的差求和的最小值 这道题其实是动态规划01背包问题 我们直接按步骤做吧 step1:定义状态表示f[i][j]表示从1到i个编号的差值里选出刚好j个数的最小操作次数 step2:推导状态转移方程 如图这就是我们的状态…...

wireshark开启对https密文抓包

HTTPS抓包解密指南 通常情况下&#xff0c;Wireshark只能抓取HTTP的明文包&#xff0c;对于HTTPS的报文需要特殊设置才能抓取。如果不进行设置&#xff0c;抓取到的都是TLS加密报文&#xff0c;这对调试工作造成了很大困难。 前言 提到HTTPS抓包&#xff0c;基本都绕不开SSL…...

AudioFlinger与AudioPoliceManager初始化流程

AF/APF启动流程 在启动AudioSeriver服务的过程中会对启动AF/APF。main_audioserver.cpp有如下代码&#xff1a; AudioFlinger::instantiate();AudioPolicyService::instantiate();AF初始化流程 1.AudioFlinger::instantiate() 1.1 AudioFlinger构造函数 void AudioFlinger:…...

网路传输层UDP/TCP

一、端口号 1.端口号 1.1 五元组 端口号(port)标识了一个主机上进行通信的不同的应用程序. 如图所示, 在一个机器上运行着许多进程, 每个进程使用的应用层协议都不一样, 比如FTP, SSH, SMTP, HTTP等. 当主机接收到一个报文中, 网络层一定封装了一个目的ip标识我这台主机, …...

Python大数据处理 基本的编程方法

目录 一、实验目的 二、实验要求 三、实验代码 四、实验结果 五、实验体会 一、实验目的 体会基本的python编程方法&#xff1b;学习python中的各类函数&#xff1b;了解python读取与写入文件的方法。 二、实验要求 输入2000年后的某年某月某日&#xff0c;判断这一天是…...

STM32F103_LL库+寄存器学习笔记06 - 梳理串口与串行发送“Hello,World“

导言 USART是嵌入式非常重要的通讯方式&#xff0c;它的功能强大、灵活性高且用途广泛。只停留在HAL库层面上用USART只能算是入门&#xff0c;要加深对USART的理解&#xff0c;必须从寄存器层面入手。接下来&#xff0c;先从最简单的USART串行发送开始。 另外&#xff0c;在接…...

硬件基础--14_电功率

电功率 电功率:指电流在单位时间内做的功(表示用电器消耗电能快慢的一个物理量)。 单位:瓦特(W)&#xff0c;简称瓦。 公式:PUI(U为电压&#xff0c;单位为V&#xff0c;i为电流&#xff0c;单位为A&#xff0c;P为电功率&#xff0c;单位为W)。 单位换算:进位为1000&#xff…...

【C#语言】C#文件操作实战:动态路径处理与安全写入

文章目录 ⭐前言⭐一、场景痛点⭐二、完整实现代码⭐三、关键技术解析&#x1f31f;1、动态路径处理&#x1f31f;2、智能目录创建&#x1f31f;3、安全的文件写入 ⭐四、进阶扩展方案&#x1f31f;1、用户自定义路径选择&#x1f31f;2、异常处理增强&#x1f31f;3、异步写入…...

Vue.js 完全指南:从入门到精通

1. Vue.js 简介 1.1 什么是 Vue.js? Vue.js(通常简称为 Vue)是一个用于构建用户界面的渐进式 JavaScript 框架。所谓"渐进式",意味着 Vue 的设计是由浅入深的,你可以根据自己的需求选择使用它的一部分或全部功能。 Vue 最初由尤雨溪(Evan You)在 2014 年创…...

在Git仓库的Readme上增加目录页

一般在编写Readme时想要增加像文章那样的目录&#xff0c;方便快速跳转&#xff0c;但是Markdown语法并没有提供这样的方法&#xff0c;但是可以通过超链接结合锚点的方式来实现&#xff0c;如下图是我之前一个项目里写的Readme&#xff1a; 例如有下面几个Readme内容&#xff…...

C# SolidWorks 二次开发 -各种菜单命令增加方式

今天给大家讲一讲solidworks中各种菜单界面&#xff0c;如下图&#xff0c;大概有13处&#xff0c;也许还不完整哈。 1.CommandManager选项卡2.下拉选项卡3.菜单栏4.下级菜单5.浮动工具栏6.快捷方式工具栏7.FeatureManager工具栏区域8.MontionManager区域 ModelView?9.任务窗…...

分布式架构-Spring技术如何能实现分布式事务

在Spring技术栈中实现分布式事务&#xff0c;可通过多种成熟方案实现跨服务或跨数据库的事务一致性管理。以下是主要实现方式及技术要点&#xff1a; 一、基于Seata框架的AT模式 ‌核心组件‌ ‌TC (Transaction Coordinator)‌&#xff1a;全局事务协调器&#xff08;独立部署…...

【RocketMQRocketMQ Dashbord】Springboot整合RocketMQ

【RocketMQ&&RocketMQ Dashbord】Springboot整合RocketMQ 【一】Mac安装RocketMQ和RocketMQ Dashbord【1】安装RocketMQ&#xff08;1&#xff09;下载&#xff08;2&#xff09;修改 JVM 参数&#xff08;3&#xff09;启动测试&#xff08;4&#xff09;关闭测试&…...