滑动窗口【基础算法精讲 03】
滑动窗口【基础算法精讲 03】滑动窗口即同向双指针209. 长度最小的子数组# 思路一先尽可能收缩再判断# while 还能缩且仍满足条件:# 缩# if 现在满足: 记录classSolution(object):defminSubArrayLen(self,target,nums): :type target: int :type nums: List[int] :rtype: int nlen(nums)ansn1left0mysum0forright,numinenumerate(nums):mysumnumwhilemysum-nums[left]target:mysum-nums[left]left1ifmysumtarget:ansmin(ans,right-left1)returnansifansnelse0# 思路二 先记录再收缩# while 满足条件:# 记录# 缩classSolution(object):defminSubArrayLen(self,target,nums): :type target: int :type nums: List[int] :rtype: int nlen(nums)ansn1left0mysum0forright,numinenumerate(nums):mysumnumwhilemysumtarget:ansmin(ans,right-left1)mysum-nums[left]left1returnansifansnelse0小节enumerate(iterable, start0)是 Python 内置函数用于同时获取索引和元素值避免手动维护计数器。fruits[apple,banana,cherry]# 默认从 0 开始fori,fruitinenumerate(fruits):print(i,fruit)# 0 apple# 1 banana# 2 cherry核心思路**滑动窗口双指针**利用单调性——数组元素为正窗口和随 right 增大而增大随 left 增大而减小目标找和 ≥ target 的最短连续子数组,因此双指针均单向移动不会回退。设计说明right窗口右边界逐个扩展left窗口左边界条件满足时收缩mysum维护窗口内元素和713. 乘积小于 K 的子数组classSolution(object):defnumSubarrayProductLessThanK(self,nums,k): :type nums: List[int] :type k: int :rtype: int # 注意k 没有正整数乘积1ifk1:return0ans0left0mul1forright,numinenumerate(nums):mul*numwhilemulk:mul//nums[left]left1# left到right之间的数乘积满足条件缩短后减少了数字一定满足ansright-left1returnans小节使用/浮点除法精度可能丢失应使用//或先判断k 1。k 1时没有子数组能满足乘积 k正整数最小乘积为 1应直接返回 0。核心思路滑动窗口 计数设计说明right扩展窗口右边界乘入新元素left收缩当乘积 ≥ k 时除以左边元素缩小乘积ans right - left 1以 right 结尾的所有满足条件的子数组个数3. 无重复字符的最长子串classSolution(object):deflengthOfLongestSubstring(self,s): :type s: str :rtype: int ans0charnumCounter()left0forright,cinenumerate(s):charnum[c]1whilecharnum[c]1:# 这里依次将left所指的元素的个数减一不一定正好是导致出现重复的元素charnum[s[left]]-1left1ansmax(ans,right-left1)returnans# 更简洁用 set 判断是否存在classSolution(object):deflengthOfLongestSubstring(self,s):char_setset()left0ans0forright,cinenumerate(s):whilecinchar_set:# 类似上述思路只是换成几何形式char_set.remove(s[left])left1char_set.add(c)ansmax(ans,right-left1)returnans# 最优用 dict 记录字符最新位置直接跳转 leftclassSolution(object):deflengthOfLongestSubstring(self,s):char_idx{}# 记录字符 - 最新下标left0ans0# 优化之处在于直接跳到重复字符的下一个位置减少不是导致重复元素的移动forright,cinenumerate(s):ifcinchar_idxandchar_idx[c]left:leftchar_idx[c]1# 直接跳到重复字符的下一个位置char_idx[c]right ansmax(ans,right-left1)returnans小节Counter()是 Pythoncollections模块中的类用于快速统计可迭代对象中元素的出现次数。fromcollectionsimportCounter# 统计字符串sabracadabracntCounter(s)# Counter({a: 5, b: 2, r: 2, c: 1, d: 1})# 统计列表nums[1,2,2,3,3,3]cntCounter(nums)# Counter({3: 3, 2: 2, 1: 1})核心思路滑动窗口 哈希计数设计说明right扩展窗口右边界逐个加入字符left收缩当窗口内出现重复字符时右移 left 直到无重复charnum(Counter)维护窗口内各字符的出现次数ans记录窗口的最大长度版本时间空间特点Counter 版O(n)O(字符集大小)通用但维护计数略冗余滑动窗口维护无重复字符区间right 扩展加入新字符出现重复时 left 收缩直到无重复记录最大窗口长度。set 版O(n)O(字符集大小)简洁只判存在性滑动窗口维护无重复字符区间right 扩展加入新字符出现重复时 left 收缩直到无重复记录最大窗口长度。dict 版O(n)O(字符集大小)最优left 直接跳转无需逐个移出字典记录字符最新下标遇到重复时直接让 left 跳到上次出现位置1无需逐个移出窗口内字符。关键是判断char_idx[c] left过滤掉窗口外的过时记录确保跳转正确性。这是滑动窗口的跳跃版将均摊复杂度从可能 O(n²) 降到严格 O(n)。3090. 每个字符最多出现两次的最长子字符串classSolution(object):defmaximumLengthSubstring(self,s): :type s: str :rtype: int ans0charnumCounter()left0forright,cinenumerate(s):charnum[c]1whilecharnum[c]2:# 这里依次将left所指的元素的个数减一不一定正好是导致出现重复的元素charnum[s[left]]-1left1ansmax(ans,right-left1)returnans# 优化 用 pos记录字符出现的前两次位置直接跳转left# 到导致不满足字符最多出现两次的元素的第一次出现的位置classSolution(object):defmaximumLengthSubstring(self,s):# 记录每个字符在窗口内的出现次数cnt[0]*26# 记录每个字符的出现位置用于快速找到第1次出现位置# pos是一个列表元素为列表的列表 即[[],[],...[]]pos[[]for_inrange(26)]left0ans0forright,cinenumerate(s):idxord(c)-ord(a)cnt[idx]1pos[idx].append(right)# 当 c 出现第3次left 直接跳到 c 第1次出现位置 1whilecnt[idx]2:first_pospos[idx][0]# c 的第1次出现位置# 移除 left 到 first_pos 之间的所有字符计数foriinrange(left,first_pos1):cnt[ord(s[i])-ord(a)]-1pos[ord(s[i])-ord(a)].pop(0)leftfirst_pos1ansmax(ans,right-left1)returnans小节[[] for _ in range(26)]用列表推导式创建 26 个独立的空列表分别存储 26 个字母的出现位置索引是处理固定小字符集时记录位置的常用技巧。核心思路滑动窗口维护字符频次 ≤ 22958. 最多 K 个重复元素的最长子数组classSolution(object):defmaxSubarrayLength(self,nums,k): :type nums: List[int] :type k: int :rtype: int ans0cnmCounter()left0forright,numinenumerate(nums):cnm[num]1whilecnm[num]k:cnm[nums[left]]-1left1ansmax(ans,right-left1)returnans小节滑动窗口维护元素频次right 扩展加入元素超过 k 次时 left 收缩直到满足条件记录最大窗口长度。每个元素最多进出窗口一次线性时间解决。核心思路滑动窗口 哈希计数2730. 找到最长的半重复子字符串classSolution(object):deflongestSemiRepetitiveSubstring(self,s): :type s: str :rtype: int nlen(s)ifn1:returnn left0ans1pair0# 窗口内相邻相同字符的对数forrightinrange(1,n):# 新加入的字符是否形成新的相邻相同对ifs[right]s[right-1]:pair1# 当相邻相同对超过1时收缩左边界whilepair1:ifs[left]s[left1]:pair-1left1# 更新最大长度ansmax(ans,right-left1)returnans小节注意边界情况字符串长度小于1题目限制的不是某个字符出现次数而是相邻相同对数 ≤ 1。核心思路滑动窗口 计数相邻相同对。right扩展时检查是否新增相邻相同对pair 1时left收缩直到只剩一对。核心是状态定义从字符频次转变为相邻相同对的数量实现 O(1) 空间的线性解法。1004. 最大连续1的个数 IIIclassSolution(object):deflongestOnes(self,nums,k): :type nums: List[int] :type k: int :rtype: int nlen(nums)ifnk:returnn ans0left0maxkkforright,numinenumerate(nums):ifnum!1:maxk-1whilemaxk0:ifnums[left]0:maxk1left1ansmax(ans,right-left1)returnans核心思路滑动窗口维护 0 的个数把翻转 k 个 0转化为窗口内最多包含 k 个 0right 扩展遇到 0 则消耗翻转机会0 的个数超过 k 时 left 收缩归还机会记录最大窗口长度。核心是用剩余翻转次数maxk作为窗口收缩的触发条件实现 O(1) 空间的线性解法2962. 统计最大元素出现至少 K 次的子数组classSolution(object):defcountSubarrays(self,nums,k): :type nums: List[int] :type k: int :rtype: int maxnummax(nums)left0# 满足最大元素至少出现K次的最大元素的下标countans0forright,numinenumerate(nums):ifnummaxnum:count1whilecountk:ifnums[left]maxnum:count-1left1ansleftreturnans核心思路滑动窗口 计数最大元素。right扩展计数maxnumcount k时left收缩到刚好不满足。关键技巧ans left以right结尾的满足条件的子数组起始位置有left个可选。设计说明maxnum数组中的最大元素固定值count窗口内maxnum的出现次数right扩展窗口右边界遇到maxnum则count 1left收缩当count k时右移left直到count kans left关键以right结尾的满足条件的子数组个数2302. 统计得分小于 K 的子数组数目classSolution(object):defcountSubarrays(self,nums,k):nlen(nums)left0mysum0# 窗口内元素和ans0forright,numinenumerate(nums):mysumnum# 收缩当得分 k 时左边界右移while(right-left1)*mysumk:mysum-nums[left]left1# 以 right 结尾的满足条件的子数组个数# 起始位置可以是 left, left1, ..., right# 共 (right - left 1) 个ansright-left1returnans小节利用正数性质实现 O(n) 线性计数。窗口满足条件时其内部所有以right结尾的更短子数组长度变小mysum变小也满足。所以ans right - left 1一次性统计所有以right结尾的合法子数组。核心思路滑动窗口 正数单调性设计说明right扩展窗口右边界加入新元素累加和left收缩当长度 × 和 k时右移 left 减小窗口mysum维护窗口[left, right]内的元素和关键更新ans right - left 11658. 将 x 减到 0 的最小操作数(建议复习)classSolution(object):defminOperations(self,nums,x):totalsum(nums)targettotal-x# 如果 target 0说明全部移除也不够iftarget0:return-1# 滑动窗口找和为 target 的最长子数组left0mysum0max_len-1# 标记是否找到forright,numinenumerate(nums):mysumnumwhilemysumtarget:mysum-nums[left]left1ifmysumtarget:max_lenmax(max_len,right-left1)# 如果没找到返回 -1ifmax_len-1:return-1# 操作次数 总长度 - 中间保留长度returnlen(nums)-max_len小节问题转换核心思路逆向思维 滑动窗口题目要求从数组两端移除元素使和等于 x求最少操作次数。逆向转换找数组中间一段连续子数组使其和等于total - x且长度最长。3795. 不同元素和至少为 K 的最短子数组长度(建议复习)classSolution(object):defminLength(self,nums,k):nlen(nums)ansn1left0cntCounter()# 窗口内元素频次unique_sum0# 不同元素的和forright,numinenumerate(nums):cnt[num]1ifcnt[num]1:# 第一次出现unique_sumnum# 收缩窗口whileunique_sumk:ansmin(ans,right-left1)# 移出 leftleft_numnums[left]cnt[left_num]-1ifcnt[left_num]0:# 该元素不再在窗口中unique_sum-left_num# 减少内存消耗delcnt[left_num]left1returnansifansnelse-1小节滑动窗口维护不同元素和用 Counter 记录窗口内元素频次只有元素首次出现时才加入unique_sum移出时只有频次降为 0 才从unique_sum减去。当不同元素和 ≥ k 时收缩窗口记录最短长度。76. 最小覆盖子串(特别难)class Solution(object): def minWindow(self, s, t): need Counter(t) # t 中各字符需要的频次 missing len(t) # 还需要匹配的字符总数 left 0 min_len float(inf) min_start 0 for right, c in enumerate(s): # 扩展窗口 if need[c] 0: # c 是 t 中需要的字符 missing - 1 # 对所有字符进行处理包括不在t中出现的字符 # 不出现的字符初始值为0t中出现的字符初始值为正数 need[c] - 1 # 收缩窗口当所有字符都匹配够时 while missing 0: # 更新最小窗口 if right - left 1 min_len: min_len right - left 1 min_start left # 移出 left 字符对所有的字符进行处理 # 对于非t中出现的字符归还后值为负数或者零最终回到零 # 对于t中出现的字符归还后大于零说明把需要的字符归回啦小于零目前的字串仍能覆盖t need[s[left]] 1 # 归还一个需求 if need[s[left]] 0: # 如果归还后还需要说明移出的是关键字符 missing 1 left 1 return s[min_start:min_start min_len] if min_len ! float(inf) else 小节python3中支持Counter直接比较进行覆盖判断Python 2Python 3Counter 比较不支持支持报错位置cnt_s cnt_t行为异常正常实际现象while条件异常导致left一直增加到越界正常核心思路滑动窗口 需求计数。用Counter记录每个字符的剩余需求missing跟踪还需匹配的字符总数。窗口满足条件时收缩找最小不满足时扩展。核心是用need[c]的正负零区分还需要、“有冗余”、“刚好够”精确处理重复字符的匹配问题。

相关新闻

WebPlotDigitizer:从图表图像中高精度提取数据的原理与实战指南

WebPlotDigitizer:从图表图像中高精度提取数据的原理与实战指南

1. 项目概述:从图表到数据的“时光机” 在科研、工程乃至市场分析的日常工作中,我们常常会遇到一个令人头疼的场景:你急需某篇论文、某个报告或者一张历史图表里的精确数据,但手头只有一张图片格式的PDF或截图,原始数据…

2026/8/2 11:30:05 阅读更多 →
大功率Grove继电器(30A)原理与应用:从Arduino到树莓派的强电控制指南

大功率Grove继电器(30A)原理与应用:从Arduino到树莓派的强电控制指南

1. 项目概述:为什么你需要一个30A的Grove继电器?如果你玩过Arduino或者树莓派,肯定接触过继电器。但当你面对一个需要控制大功率设备——比如一个1.5匹的空调、一个电热水壶,甚至是一台小型机床电机——的项目时,那些常…

2026/8/2 11:30:05 阅读更多 →
Germinal AI:表位靶向抗体设计的生成式人工智能流程详解

Germinal AI:表位靶向抗体设计的生成式人工智能流程详解

1. 项目概述:从“大海捞针”到“精准制导”的抗体设计革命 在抗体药物研发和基础免疫学研究领域,我们长期面临一个核心痛点:如何高效、精准地获得能够特异性结合目标蛋白上某一特定区域(即“表位”)的抗体?…

2026/8/2 11:29:05 阅读更多 →

最新新闻

周末接了个外包急单,我用这款AI应用开发工具3小时搞定多端原型

周末接了个外包急单,我用这款AI应用开发工具3小时搞定多端原型

前言: 上周末临时接了个朋友的外包私活,需求不复杂:做一个本地生活预约的微信小程序,外加一个H5网页版的商家管理后台。虽然业务逻辑简单,但涉及到多端适配、前端页面、后端数据库设计以及基础接口,原本评估…

2026/8/2 12:18:11 阅读更多 →
整理了一套 Go 系统教程:131 篇从语法到 K8s Operator,附完整学习路径

整理了一套 Go 系统教程:131 篇从语法到 K8s Operator,附完整学习路径

写在前面 学 Go 这件事,说难不难,说简单也不简单。 语法层面,25 个关键字,一下午就能看完;但要真把 Go 用好——写出高并发的服务、调好 GC、设计合理的微服务架构、写一个 K8s Operator——中间隔着的不只是一本语法…

2026/8/2 12:18:11 阅读更多 →
AI聊天机器人对心理健康的影响与健康使用边界探讨

AI聊天机器人对心理健康的影响与健康使用边界探讨

1. 从“聊天”到“聊傻”:Nature研究引发的AI社交深度思考 最近,一篇发表在《自然》杂志上的研究,标题相当抓人眼球,直指一个我们越来越习以为常的现象:与AI聊天机器人进行深度、频繁的交流,可能会对人的认…

2026/8/2 12:18:11 阅读更多 →
气象统计方法期末复习:从核心概念到实战应用全解析

气象统计方法期末复习:从核心概念到实战应用全解析

1. 项目概述:一份来自“过来人”的期末复习地图 又到期末了,是不是感觉《气象统计方法》这门课的知识点像一团乱麻,公式多、概念杂,看书看得头大,做题做得心慌?别急,我当年也是这么过来的。这门…

2026/8/2 12:18:11 阅读更多 →
可解释性AI与因果推断如何驱动脑科学研究范式变革

可解释性AI与因果推断如何驱动脑科学研究范式变革

1. 项目概述:当AI成为脑科学的“翻译官” 最近几年,AI和脑科学的交叉领域火得不行,几乎成了科研和产业的双重风口。你可能会好奇,这两个看似一个在“云端”一个在“颅内”的领域,到底能碰撞出什么火花?简单…

2026/8/2 12:18:11 阅读更多 →
Arduino驱动reTerminal E系列电子纸:从零实现低功耗显示项目

Arduino驱动reTerminal E系列电子纸:从零实现低功耗显示项目

1. 项目缘起:为什么是reTerminal E系列电子纸?最近在折腾一个需要长时间显示信息,但又不想一直插着电的项目,比如一个放在门口的天气预报牌,或者一个厨房里的定时器。用普通的LCD屏吧,功耗是个大问题&#…

2026/8/2 12:17:11 阅读更多 →

日新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/2 6:34:16 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/2 2:47:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/2 0:23:22 阅读更多 →