面试难点!常用算法技巧之“滑动窗口”

算法简介

滑动窗口,顾名思义,就是有一个大小可变的窗口,左右两端方向一致的向前滑动(右端固定,左端滑动;左端固定,右端滑动)。

可以想象成队列,一端在push元素,另一端在pop元素,如下所示:

假设有数组[a b c d e f g h]
一个大小为3的滑动窗口在其上滑动,则有:

[a b c][b c d][c d e][d e f][e f g][f g h]

适用范围

  • 1、一般是字符串或者列表

  • 2、一般是要求最值(最大长度,最短长度等等)或者子序列

算法思想

  • 1、在序列中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个窗口。
  • 2、先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的序列符合要求。
  • 3、此时,停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的序列不再符合要求。同时,每次增加 left前,都要更新一轮结果。
  • 4、重复第 2 和第 3 步,直到 right 到达序列的尽头。
    思路其实很简单:第 2 步相当于在寻找一个可行解,然后第 3 步在优化这个可行解,最终找到最优解。左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动。

算法模板

1、单层循环

def template():# 初始化滑动窗口两端left = right = 0# 序列及序列长度seq, seq_len = xx, xx# 滑动窗口序列slide_win = []# 结果值rst = xxwhile right < seq_len:slide_win.append(seq[right])# 还没找到一个可行解if not avaliable(slide_win):# 扩大窗口right += 1else:# 找到一个可行解,更新结果值rst = update()# 缩小窗口left += 1

2、双层循环

def template():# 初始化滑动窗口两端left = right = 0# 序列及序列长度seq, seq_len = xx, xx# 滑动窗口序列slide_win = []# 结果值rst = xxwhile right < seq_len:slide_win.append(seq[right])# 还没找到一个可行解if not avaliable(slide_win):# 扩大窗口right += 1continue# 循环更新可行解while avaliable(slide_win):# 找到一个可行解,更新结果值rst = update()# 缩小窗口left += 1

模板只是一个解题思路,具体的题目可能需要具体分析,但是大体框架是不变的。
记住: 多刷题,多总结,是王道

算法示例

1、最长不含重复字符的子字符串

from collections import dequeclass Solution(object):def lengthOfLongestSubstring(self, s):""":type s: str:rtype: int"""if not s:return 0index = 0# 因为这个滑动窗口需要从一端进,一端出,因此考虑采用队列slide_win = deque()# 因为在滑动过程中需要不断的从窗口中增减元素,因此需要一个变量来保持最大窗口长度max_len = 1while index < len(s):# 一个小的优化点:还没有遍历的元素长度加上当前的窗口长度已经小于最大窗口长度,则直接返回结果if len(slide_win) + (len(s) - index) <= max_len:return max_len# 如果当前元素没有在滑动窗口中,则加入,并且窗口扩大if s[index] not in slide_win:slide_win.append(s[index])index += 1else:# 如果当前元素已经在窗口中有值,则更新最大窗口长度max_len = max(max_len, len(slide_win))# 窗口缩小,对端不变slide_win.popleft()return max(max_len, len(slide_win))

2、绝对差不超过限制的最长连续子数组

import heapqclass Solution(object):def longestSubarray(self, nums, limit):""":type nums: List[int]:type limit: int:rtype: int"""if not nums:return 0len_nums = len(nums)# 因为需要比较子列表中的最大差值,即需要知道子列表中的最大值和最小值# 因此采用大顶堆和小顶堆max_hq = []min_hq = []# 滑动窗口的前后索引left = 0right = 0# 在滑动窗口的过程中,更新最大的窗口长度max_win = 1while right < len_nums:if len_nums - left <= max_win:return max_win# 将当前元素及其索引放入堆中,因为python只有小顶堆,因此这里采用负值来模拟大顶堆heapq.heappush(max_hq, (-nums[right], right))heapq.heappush(min_hq, (nums[right], right))# 窗口的最大差值diff = -max_hq[0][0] - min_hq[0][0]# 最大差值在允许范围内,窗口后边向前滑动,左边保持不变if diff <= limit:right += 1continue# 最大差值超过范围:# 更新最大窗口长度max_win = max(max_win, right - left)# 保证滑动窗口内的最大差值在允许范围内while -max_hq[0][0] - min_hq[0][0] > limit:# 去掉大顶堆中在滑动窗口之外的所有最大元素while max_hq[0][1] <= left:heapq.heappop(max_hq)# 去掉小顶堆中在滑动窗口之外的所有最小元素while min_hq[0][1] <= left:heapq.heappop(min_hq)left += 1return max(max_win, right - left)

3、无重复字符的最长子串

from collections import deque
class Solution(object):def lengthOfLongestSubstring(self, s):""":type s: str:rtype: int"""if not s:return 0index = 0# 因为这里需要从窗口的两端进行元素的增加或减少,因此采用双端队列slide_win = deque()# 题目要求最长子串长度,因此需要在滑动过程中更新最大长度max_len = 0while index < len(s):ch = s[index]# 如果当前元素不在窗口中,则加入窗口if ch not in slide_win:slide_win.append(ch)# 窗口的右端向前滑动,左端不变(扩大窗口)index += 1else:# 当前元素已经存在窗口中,即表示找到一个可行解,更新最大长度max_len = max(max_len, len(slide_win))Java开发交流君样:756584822# 将窗口中在当前元素值之前的元素全部移除掉,即窗口左端向前滑动,右端不变(缩小窗口)while ch in slide_win:slide_win.popleft()return max(max_len, len(slide_win))

4、替换后的最长重复字符

class Solution(object):def characterReplacement(self, s, k):""":type s: str:type k: int:rtype: int"""if not s:return 0# 滑动窗口的左右两端left = 0right = 0# 记录每个字符出现的频率ch_fre = defaultdict(int)# 记录字符出现的最大频率max_fre = 0# 在窗口滑动过程中,更新最大长度max_len = 0while right < len(s):ch = s[right]# 当前字符频率加1ch_fre[ch] += 1# 更新字符出现过的最大频率max_fre = max(max_fre, ch_fre[ch])# 如果滑动窗口的长度大于字符能够达到的最大频率# 即窗口内不可能出现全是重复的字符,因此需要将窗口的左端向前滑动(缩小窗口)if right - left + 1 > max_fre + k:# 滑动出去的字符需要将其频率减1ch_fre[s[left]] -= 1left += 1# 此时滑动窗口内全是重复字符,更新最大长度值 max_len = max(max_len, right - left + 1)# 滑动窗口的右端向前滑动(扩大窗口)right += 1
//Java开发交流君样:756584822return max_len

算法总结

滑动窗口算法就是用以解决数组/字符串的子元素问题
滑动窗口算法可以将嵌套的for循环问题,转换为单循环问题,降低时间复杂度

最后,祝大家早日学有所成,拿到满意offer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回公司上班

回到公司上班了&#xff0c;悠闲的生活从此开始.....

10岁吊打职业教师的天才,仅用10篇论文称霸数学界160多年,40岁英年早逝却迄今无人超越...

全世界只有3.14 % 的人关注了青少年数学之旅今天超模君就给大家讲讲黎曼。人类历史上最伟大的数学天才的德国数学家是十九世纪数学界的巅峰——节选自《数学之旅 闪耀人类的54个数学家》1826年&#xff0c;黎曼作为家中的老二在德国汉诺威的布雷斯伦茨村出生了。他的父亲是村里…

NET问答: 如何集中化统一验证 Authorization

咨询区 Felipe Deveza&#xff1a;我自己实现了一个 basic 验证&#xff0c;现在我的做法是在每一个 Action 中都提取 Request.Headers["Authorization"] 进行权限验证。[HttpGet] public IActionResult Get() {string token Request.Headers["Authorization&q…

c#操作excel后关闭excel.exe的方法

C#和Asp.net下excel进程一被打开,有时就无法关闭, 尤其是website.对关闭该进程有过GC、release等方法&#xff0c;但这些方法并不是在所有情况下均适用。 于是提出了kill process的方法, 目前我见过的方法多是用进程创建时间筛选excel.exe进程, 然后kill 。 这样的…

22届腾讯暑期实习三轮面试面经(已oc)

投递岗位&#xff1a;IEG非工作室&#xff0c;java选手&#xff0c;岗位是C和go 3.6找同学内推 3.8一面&#xff1a;&#xff08;电话面试&#xff0c;45min&#xff09; 1、哈希表、concurentHashMap源码&#xff0c;扩容机制 2、多线程死锁、解决办法 3、线程池介绍一下&am…

AngularJS学习---REST和自定义服务(REST and Custom Services) ngResource step 11

1.切换目录 git checkout step-11 npm start 2.效果图 效果图和step 10的没有什么差别,这里主要的改动都是代码,代码做了很多优化,这里效果图就不再贴出来了. 3.实现代码 step-10和step-11之间的差别:https://github.com/angular/angular-phonecat/compare/step-10...step-11 D…

面试可以,但别打扰我睡觉! | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源科技九洲君&#xff0c;侵权删&#xff09;

使用网页对话框来显示图片 window.open()

这个主要用到了JS中的 window.open(url,windowname,location)url 目标窗口的url 如果url 是一个空字符串&#xff0c;浏览器将打开一个空白窗口windowname window对象名称location 窗口属性设置可选参数Default.aspx 页如下放置一个linkbutton,并写下事件处理protected void L…

基于事件驱动架构构建微服务第3部分:Presenters, Views和Controllers

原文链接&#xff1a;https://logcorner.com/building-microservices-through-event-driven-architecture-part3-presenters-views-and-controllers/在本文中&#xff0c;我将实现Presentation(展示层)。这里的展示层不是指用户界面而是Web API。也可以在实现展示层之前先实现r…

hashtable与HashMap区别

看到了很多的面试题集里都有这么一个题:HashMap和Hashtable的区别,自己也看了好几遍了,总是不记得,写下来当是一次笔记吧. 区别一它们的父类不同 public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializabl…

牛逼!不得不服,第一次有人把Java 反射机制讲解这么透!

反射概述 什么是反射 将类的各个组成部分封装为其他对象的过程就叫做 反射&#xff0c;其中 组成部分 指的是我们类的 成员变量&#xff08;Field&#xff09;、构造方法&#xff08;Constructor&#xff09;、成员方法&#xff08;Method&#xff09;。 使用反射的优缺点 …

拿破仑最欣赏的数学家,师从拉格朗日,撕逼泊松,一生痴迷热学最后却死于热学...

全世界只有3.14 % 的人关注了 青少年数学之旅 这几天&#xff0c;终于变凉了&#xff0c;超模君再也不用被热死了。 但炎热夏日的离去&#xff0c;也让超模君想起了那个和热脱不了关系的数学家——傅里叶。 “对自然界的深入研究是数学发现最丰富的源泉” ——节选自 《数学之旅…

Mysql ID重新排列

我们经常会遇到&#xff0c;在删除数据库某条记录时&#xff0c;原来的ID排序会有间隔&#xff0c;比如删除了ID为8的数据,这个表的ID排序就会从7直接到9, 那我们如何解决这个ID重新排列的问题呢? 只需一下三步: 1.删除这个表的ID ALTER TABLE table_name DROP id; 2.重新建立…

java基础进阶(文件列表,线程,线程组)编程实例(4篇)

此处刊登代码均测试通过&#xff0c;完全准确&#xff01; import java.io.*; public class DirList{ public static void main(String[] args){ try{ File pathnew File("."); /*“.”指当前目录*/ String[] list; if(args.length0) listpath.list();/*列出当前文件…

记一次 .NET 某智慧水厂API 非托管内存泄漏分析

一&#xff1a;背景 1. 讲故事七月底的时候有位朋友在wx上找到我&#xff0c;说他的程序内存占用8G&#xff0c;托管才占用1.5G&#xff0c;询问剩下的内存哪里去了&#xff1f;截图如下&#xff1a;从求助内容看&#xff0c;这位朋友真的太客气了&#xff0c;动不动就谈钱&…

失业日志:2009年10月12日星期一

反正也是空&#xff0c;突发奇想把这段失业的心态记录下来&#xff0c;也挺有趣的。 从进行产品支持&#xff0c;每天过着算是有规律的日子&#xff0c;到狠下心放弃产品技术支持&#xff0c;经历了三次辞职。最后一次&#xff0c;终于放下心头的石头&#xff0c;朝自己喜欢的方…

直接开撸! 阿里Spring高频面试题泄露,持续更新~

阿里HR面试核心的几个问题&#xff1a; 1、你为什么离职&#xff1f; 2、你怎么看待自己的职业生涯&#xff1f;&#xff08;包括怎么平衡家庭和工作的关系、加班、选择一家公司时的考量、location等&#xff09; 3、薪资期望 4、项目中遇到的最大挑战是什么&#xff1f;怎么…

重磅!Nature盘点年度十佳论文,生命科学占据半壁江山,中国学者表现亮眼

全世界只有3.14 % 的人关注了青少年数学之旅科学是人类进步的阶梯&#xff01;在当今社会&#xff0c;科学技术的发展进步将为人类社会带来巨大的效益&#xff0c;毫不夸张的说&#xff0c;科学指引并推着着人类文明的进程。基础科学作为科学技术的理论基石&#xff0c;其重要性…

zend guard6的使用

1.生成key edit->preferences->license Keys->generate 2.新建product license文件 3.新建Zend Guard项目文件 需要注意新建项目的第二项需要英文路径 4.在项目上按右键 选择configure 初始界面是 如果要用做授权,点击security按键 然后设置license文件等 附上php.in…

回忆一 --- 去年6月面试进入公司的日子

2007年6月&#xff0c;我投了一份简历到后来一直工作的公司应聘&#xff0c;做对日软件外包业务的&#xff0c;不过有翻译&#xff0c;对日语要求不高。我投递了简历的第二天被通知面试。还好&#xff0c;因为技术考题偏于数据结构和算法&#xff0c;而不是实际项目经验&#x…