基础算法练习--滑动窗口(日更中)

算法介绍

滑动窗口算法来自tcp协议的一种特性,它的高效使得其也变成了算法题的一种重要考点.滑动窗口的实现实际上也是通过两个指针前后遍历集合实现,但是因为它有固定的解题格式,我将其单独做成一个篇章.

滑动窗口的解题格式:

首先,定义两个指针left和right,与双指针不同的是,它们一开始都指向同一个地方(通常是数组中的第一个元素).

接着,让right指针后移,把right指针指向的元素"进窗口".

随后,判断当前"窗口"是否满足题目要求.

最后,如果不满足条件就要让left指针指向的元素"出窗口",left指针再后移.

上述解题格式中不难发现,"窗口"实际上就是一个连续的区间,滑动窗口算法主要用来处理某个连续区间上的问题,左右指针同步遍历将O(n^2)的时间复杂度降低为O(n),是一种十分高效,巧妙的算法.

习题讲解

1. 长度最小的子数组

209. 长度最小的子数组

题目解析

难点:

要求出所有满足条件中的子数组中最短的长度,难以使用暴力的方式求解.

算法应用:

子数组:在给定数组中连续取出某个区间得到的数组.这题就是求这个区间的最短长度,就可以使用滑动窗口算法进行解答.定义两个指针left和right,指向数组的第一个元素.由于这题关注某个连续区间的和的具体大小,需要定义一个sum变量维护区间上的和,一个ret变量记录答案.

进窗口: right指针指向的元素直接进窗口(sum+=nums[right])一般来说滑动窗口算法中,入窗口的限制条件十分少.

判断+出窗口: 如果当前的区间和小于target(不满足题目答案要求),不用更新答案,直接后移right指针即可;如果当前的区间和大于等于target(因为我们要求最小的区间长度,为了求这个最优解,应该确保窗口内的和尽量保持在小于target,需要出窗口,否则在本题下得到的必定不是最优解),一边更新答案,维护sum变量的值,一边出窗口(sum-=nums[left]),并将left指针右移,直到区间内的和小于target.

操作细节:

记录答案的ret变量初始化应该为最大值,最后返回时判断其是否仍为最大值,若还是最大值,需要返回0代替.

出窗口时,需要使用while循环而非if判断,虽然"进窗口"是一次循环只有一个元素进入,但是"出窗口"并没有这个限制,需要关注题目的具体条件,"出窗口"一定要"出到不能再出为止".

代码实现:

public int minSubArrayLen(int target, int[] nums) {int sum = 0;int ret = Integer.MAX_VALUE;for(int left=0,right=0; right<nums.length; right++) {sum += nums[right];while (sum >= target) {ret = Math.min(ret,right-left+1);sum -= nums[left];left++;}}return ret == Integer.MAX_VALUE ? 0 : ret;}

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

3. 无重复字符的最长字串

题目解析

难点:

要求出所有满足条件中的字串中最长的长度,难以使用暴力的方式求解,这道题和上道题十分相似,可以自己先行尝试.

算法应用:

子串:在给定字符串中连续取出某个区间得到的字符串.这题就是求这个区间的最长长度,就可以使用滑动窗口算法进行解答.为了方便,我们先将字符串转为字符数组.

定义两个指针left和right,指向数组的第一个元素.这题关注某个连续区间内不能有重复字符串,需要定义一个哈希表(用数组模拟)记录区间内出现的字符及其次数,一个ret变量记录答案.

进窗口: right指针指向的元素直接进窗口(哈希表进行记录).

判断+出窗口: 如果当前的区间内有重复字符就需要出窗口,但是我们出窗口的判断在每一次循环中都会执行,如果本次出现了重复的字符,只可能是s[right]这个字符重复了(本次循环中只有这一个媳妇进了窗口,而在进窗口前我们又保证了窗口内没有重复元素).那我们就要出窗口找到上一个出现的s[right]字符,直到将它出窗口后,这个过程才结束.出窗口过程中要不断维护哈希表.直到出窗口结束,才能更新ret的值,这题与上题的不同之处就在此,上题是出窗口到"不满足答案条件的窗口"为止,本题是出窗口到"满足答案条件的窗口"为止,这就是求最短与最长区间长度的区别.

操作细节:

使用数组模拟哈希表,由于字符串中有字母以外的字符,需要定义一个足够长的数组,防止越界.

由于求最长的满足条件字串的长度,ret在定义时初始化为0,更新时注意字串长度为right-left+1.

代码实现:

public int lengthOfLongestSubstring(String ss) {int[] hash = new int[128];char[] s = ss.toCharArray();int ret = 0;for (int left=0,right=0; right<s.length; right++) {hash[s[right]]++;while (hash[s[right]]>1) {hash[s[left]]--;left++;}ret = Math.max(ret,right-left+1);}return ret;}

3. 将x减少到0的最少操作数

1658. 将x减少到0的最少操作数

题目解析

难点:

这道题目中告诉我们,减少的规则是对数组两端进行减少操作,但是我们并不知道到底是操作左边还是右边,那么就需要使用到逆向思维.

算法应用:

题目要求我们一共减少x(所有减少元素的和为x),所使用的操作数(也就是减少的元素的个数).我们可以将其转化为:求一个区间和为 target=sum-x 的区间的最长长度(sum是初始数组中所有元素的和),拿原始数组长度减去这个最长长度就得到了我们需要的"最少操作数".

这里仍然使用sum变量记录区间内元素的和,使用前需要置0.(sum = 0)

进窗口: sum += nums[right].

出窗口: 如果sum > target,原因是我们需要找和为target的区间,如果大于target还不出窗口,后面的元素又都是正的,相加必然只会导致sum越来越大,不可能趋近等于target,出窗口直到sum<=target.

判断: 由题意,当sum = target时,才更新答案ret.

操作细节:

计算target=sum - x时,如果target<0,直接返回-1,因为题目条件中:每个元素都大于0,不可能有几个正数相加得到一个负数.但是target=0是合法的,可以通过减少所有的元素得到.

ret初始化的值为-1,如果最后ret值仍为-1,直接返回-1,说明不存在满足题意的情况;如果不是-1,记得返回n-ret(n为原始数组的长度),因为我们是你想思维进行解题的.

更新答案ret时,注意区间长度为right-left+1.

代码实现:

public int minOperations(int[] nums, int x) {int sum = 0,n = nums.length;for (int num : nums) sum += num;int target = sum - x;if (target<0) return -1;int ret = -1;sum = 0;for (int left=0,right=0; right<n; right++) {sum += nums[right];while (sum>target) {sum -= nums[left];left++;}if (sum == target) {ret = Math.max(ret, right-left+1);}}return ret == -1 ? -1 : n-ret;}

4. 水果成篮

904. 水果成篮

题目解析

难点:

这道题目相比前面的题目多了一些判断操作,但是读者可以根据前面的讲解,先自行尝试.

提示:要考虑维护窗口内水果种类的数量.

算法应用:

题目要求我们去求一个最长区间的长度,在这个区间内至多只能有两种水果.我们就需要定义一个哈希表(数组模拟)来记录窗口内各种水果出现的次数,同时需要定义一个kind变量维护水果的种类数量.

fruits[i]是某一种水果,hash[fruits[i]]是fruits[i]这种水果在窗口内出现的次数.

判断+进窗口: 先判断hash[fruits[right]]的值是否为0,如果为0,说明水果的种类在当前窗口内没出现过,再增加hash[fruits[right]]的值,维护kind变量(kind++).

出窗口+判断: 如果kind>2(超出水果篮子的数量)就需要进行出窗口操作.这时,需要注意我们是先去减少hash[fruits[left]]的值,再去判断是否减少到0,如果减少到0,说明fruits[left]这种水果在进行出窗口操作后不再出现在当前窗口中,维护kind变量(kind--).(如果调换这个顺序,读者可以自行探究会发生什么).

更新答案ret的值.

调换顺序的情况:

如果先进窗口(hash[fruits[right]]++)再判断hash[fruits[right]]的值是否为0,就会发现进窗口的水果,都已存在再窗口中,kind不会++;如果先判断hash[fruits[left]]的值是否为0再出窗口(hash[fruits[left]]--),就会发现出窗口的水果,都仍存在在窗口中,kind不会--.

操作细节:

这道题的判断与操作先后顺序十分重要,如果顺序颠倒,kind变量就不能得到正确的维护,继而得不到正确答案.

这道题中元素的数值仅仅表示不同种类的水果,而不是水果的个数.

更新答案ret时,注意区间长度为right-left+1.

代码实现:

public int totalFruit(int[] fruits) {int n = fruits.length;int kind = 0;int ret = 0;int[] hash = new int[100000];for (int left=0,right=0; right<n; right++) {int in = fruits[right];//进窗口,先判断再加if (hash[in]++==0) kind++;while (kind>2) {int out = fruits[left];left++;//出窗口,先减再判断if (--hash[out]==0) kind--;}ret = Math.max(ret, right-left+1);}return ret;}

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

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

相关文章

C#如何快速获取P/Invoke方法签名

使用API函数已经好几年了&#xff0c;封装函数签名基本是参照MSDN上的文档&#xff0c;然后再做数据类型对应。 虽然有 pinvoke.net 这个网站&#xff0c;但基本很少使用。一方面是想多动手&#xff0c;另一方面是因为各种数据类型基本都用过了&#xff0c;都能自己在C#中 对应…

人脑与机器连接:神经科技的伦理边界探讨

内容概要 在当今科技飞速发展的时代&#xff0c;人脑与机器连接已成为一个引人注目的前沿领域。在这一背景下&#xff0c;神经科技的探索为我们打开了一个全新的世界&#xff0c;从脑机接口到人工智能的飞跃应用&#xff0c;不仅加速了技术的进步&#xff0c;更触动了我们内心…

这么多优秀的 AI 大模型,我应该选择哪个呢?

前两次&#xff0c;我们向大家介绍了当前全球最有名的总共 11 个 AI 大模型。在此期间&#xff0c;openAI 于 8月 6 日 最新推出另了一个超强 AI 大模型 —— GPT-4o&#xff08;Aug 6&#xff09;&#xff0c;强势跻入全球前列。不得不说&#xff0c;这才多久&#xff0c;open…

软件开发设计管理文档,项目设计规程制度,项目开发规程,项目建设方案文档(word原件)

2 过程总体描述 2.1 过程概述 2.2 过程流程图 3 过程元素描述 3.1 产品方案 3.2 产品设计 3.3 产品实现 获取方式&#xff1a;本文末个人名片直接获取。 软件资料清单列表部分文档清单&#xff1a;工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xf…

【taro react】 ---- 常用自定义 React Hooks 的实现【六】之类渐入动画效果的轮播

1. 效果 2. 场景 css 效果实现:可以看到效果图中就是一个图片从小到大的切换动画效果,这个效果很简单,使用 css 的 transform 的 scale 来实现图片的从小到大的效果,切换就更加简单了,不管是 opacity 还是 visibility 都可以实现图片的隐藏和显示的切换。React.Children.m…

2024年转行指南:大学生进军就业前景广阔的领域——人工智能大模型

据教育部数据统计&#xff0c;2024高校毕业生规模预计达1179万人&#xff0c;将再创历史新高&#xff0c;“就业难”仍是当前大学毕业生需要直面的问题。在此背景下&#xff0c;选择一个就业前景好的专业尤为重要。 究竟学什么样的专业好就业呢&#xff1f;给毕业生们推荐3个当…

重学SpringBoot3-整合 Elasticsearch 8.x (一)客户端方式

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-整合 Elasticsearch 8.x &#xff08;一&#xff09;客户端方式 1. 为什么选择 Elasticsearch&#xff1f;2. Spring Boot 3 和 Elasticsearch 8.x 的集…

【网络安全渗透测试零基础入门】Vulnhub靶机Kioptrix level-4 多种姿势渗透详解,收藏这一篇就够了!

前言 这是阳哥给粉丝盆友们整理的网络安全渗透测试入门阶段Vulnhub靶场实战阶段教程 喜欢的朋友们&#xff0c;记得给我点赞支持和收藏一下&#xff0c;关注我&#xff0c;学习黑客技术。 环境配置 服务版本探测&#xff1a;sudo nmap -sT -sV -sC -O -p22,80,139,445 22端…

由中文乱码引来的一系列学习——Qt

前言 解决中文引起的乱码&#xff0c;并不难&#xff0c;网上一搜就有好几个方法任君选择&#xff0c;但是解决乱码的这些方法的原理是什么&#xff0c;我一直没太明白。 这次项目需要在Android环境下运行&#xff0c;而根据Qt跨平台的特性&#xff0c;我一般是在Windows环境…

浅析数据库缓存一致性问题

在真实的业务场景中&#xff0c;我们的业务的数据——例如订单、会员、支付等——都是持久化到数据库中的&#xff0c;因为数据库能有很好的事务保证、持久化保证。但是&#xff0c;正因为数据库要能够满足这么多优秀的功能特性&#xff0c;使得数据库在设计上通常难以兼顾到性…

element plus el-form自定义验证输入框为纯数字函数

element plus 的el-form 使用自定义验证器&#xff0c;验证纯数字&#xff0c;禁止输入小数、中文、字母、特殊符号。input的maxlength为最大输入多少位长度 效果图 <el-form ref"dataFormRef" :model"dataForm" :rules"dataRules" label-w…

jira如何查看历史Sprint

方法一&#xff1a;通过看板模块查看历史 Sprint 进入看板模块 在项目的看板中&#xff0c;找到并点击“模块项”。在右侧历史记录中选择一个模块项。 查看 Sprint 历史 进入模块项界面后&#xff0c;点击“搜索”按钮旁边的“更多”下拉菜单。勾选“Sprint”选项&#xff0c;…

阿里云 DataWorks 正式支持 SelectDB Apache Doris 数据源,实现 MySQL 整库实时同步

SelectDB 是由飞轮科技基于 Apache Doris 内核打造的现代化数据仓库&#xff0c;支持大规模实时数据上的极速查询分析。 通过实时、统一、弹性、开放的核心能力&#xff0c;能够为企业提供高性价比、简单易用、安全稳定、低成本的实时大数据分析支持。SelectDB 具备世界领先的实…

OV(企业型)通配符域名SSL证书

SSL证书是由CA机构签发的&#xff0c;相信这一点大家都知道&#xff0c;然而目前全世界兼容性可以达到99%机构仅有&#xff1a;GlobalSign、DigiCert、Sectigo、Certum&#xff0c;最后一家还是勉强。 SSL证书选择OV&#xff08;国内有人称之为企业型&#xff09;其实就是实名…

软考系统分析师知识点三五: 考前强记知识点

前言 今年报考了11月份的软考高级&#xff1a;系统分析师。 考试时间&#xff1a;11月9日。 倒计时&#xff1a;2天。 目标&#xff1a;优先应试&#xff0c;其次学习&#xff0c;再次实践。 复习计划第四阶段&#xff1a;考前强记知识点。 考前强记知识点 系统分析主要任…

基础算法——排序算法(冒泡排序,选择排序,堆排序,插入排序,希尔排序,归并排序,快速排序,计数排序,桶排序,基数排序,Java排序)

1.概述 比较排序算法 算法最好最坏平均空间稳定思想注意事项冒泡O(n)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)Y比较最好情况需要额外判断选择O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)N比较交换次数一般少于冒泡堆O( n l o g n nlogn nlogn)O( n l o g n nlogn nlogn)O( n l…

探索 Python 视频编辑新纪元:MoviePy库的神秘面纱

文章目录 探索 Python 视频编辑新纪元&#xff1a;MoviePy 库的神秘面纱第一部分&#xff1a;背景介绍第二部分&#xff1a;MoviePy 是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;简单的库函数使用方法第五部分&#xff1a;结合场景使…

计算机网络:网络层 —— 多播路由选择协议

文章目录 多播路由选择协议多播转发树构建多播转发树基于源树的多播路由选择建立广播转发树建立多播转发树 组共享树的多播路由选择基于核心的生成树的建立过程 因特网的多播路由选择协议 多播路由选择协议 仅使用 IGMP 并不能在因特网上进行IP多播。连接在局域网上的多播路由…

Jenkins插件使用问题总结

Git Push插件 插件介绍 主要是用于git推送代码到远程仓库中使用&#xff0c;插件地址 pipeline中使用 官方说明中只有一句代码gitPush(gitScm: scm, targetBranch: env.BRANCH_NAME, targetRepo: origin) 流水线语法中也做的不齐全所以一开始我老是设置错&#xff0c;导致代…

【命令操作】Linux三剑客之awk详解 _ 统信 _ 麒麟 _ 方德

原文链接&#xff1a;【命令操作】Linux三剑客之awk详解 | 统信 | 麒麟 | 方德 Hello&#xff0c;大家好啊&#xff01;今天带来一篇关于Linux三剑客之awk命令详解的文章。在文本处理工具中&#xff0c;awk以其强大的文本筛选、格式化和数据处理功能而闻名。它能够在处理结构化…