【算法】基础算法002之滑动窗口(一)

👀樊梓慕:个人主页

 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》《算法》

🌝每一个不曾起舞的日子,都是对生命的辜负


目录

前言

1.长度最小的子数组

滑动窗口类问题解题思路大纲:

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

3.最大连续1的个数Ⅲ

4.将 x 减到 0 的最小操作数(medium)


前言

本篇文章主要会讲解滑动窗口的解题思想,滑动窗口实际上就是利用双指针的基础思想,并且利用单调性进行解题的方法。

滑动窗口所用到的双指针是用来维护这个所谓的『 窗口』,所以这两个指针是『 同向』且『 不回退』的,这也就决定了滑动窗口解题的时间复杂度最多为O(2N) 即O(N),所以滑动窗口是一种非常优秀的算法思想。

那么滑动窗口思想具体的应用,以及如何分析判断是否适用滑动窗口解题呢?


欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。

=========================================================================

GITEE相关代码:🌟樊飞 (fanfei_c) - Gitee.com🌟

=========================================================================


1.长度最小的子数组

209. 长度最小的子数组 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/minimum-size-subarray-sum/

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

如果依照暴力枚举的策略,解题思路大致如下:

利用双指针,一个指针固定,移动另一个指针,当两个指针中间的所有元素和大于等于目标值target时,记录此时的长度,然后循环往复,求长度最小值。

代码如下:

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {// 记录结果int ret = INT_MAX;int n = nums.size();// 枚举出所有满⾜和⼤于等于 target 的⼦数组[start, end]// 由于是取到最⼩,因此枚举的过程中要尽量让数组的⻓度最⼩// 枚举开始位置for (int start = 0; start < n; start++){int sum = 0; // 记录从这个位置开始的连续数组的和// 寻找结束位置for (int end = start; end < n; end++){sum += nums[end]; // 将当前位置加上if (sum >= target) // 当这段区间内的和满⾜条件时{// 更新结果,start 开头的最短区间已经找到ret = min(ret, end - start + 1);break;}}}// 返回最后结果return ret == INT_MAX ? 0 : ret;}
};

可其实这其中有太多可以忽略掉的枚举区间,我们来分析一下:

本题要求的是长度最小子数组,所以此时一定是要更新left的位置即可,这就达到了不回退的目的。

注意:要在移动left之前更新结果。

所以此类问题,我们可以将left和right中间的区域看作一块窗口,该窗口不断的向后移动,直到right超出数组为止。

在这一过程中:

  • right移动导致元素进入窗口的行为我们称为『 进入窗口』;
  • left移动导致元素离开窗口的行为我们称为『 离开窗口』;
  • 判断left和right维护的窗口是否满足题目条件我们称为『 判断』;
  • 满足题目条件时更新结果的行为我们称为『 更新结果』。

所以以上这些步骤就构成了『 滑动窗口』类问题的解题思路。

滑动窗口类问题解题思路大纲:

①left=0,right=0;

②进入窗口;

③判断;        

        离开窗口;

④更新结果;

其中更新结果取决于具体的题目要求,『 就题论题』。

比如本题就需要在『 离开窗口』之前『 更新结果』。

有了思路,画图独立完成代码,不要直接看博主的代码。

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int left=0,right=0;int size=nums.size();int sum=0;int len=INT_MAX;while(right<size){sum+=nums[right];//进入窗口while(sum>=target)//判断{len=min(len,right-left+1);//更新结果sum-=nums[left++];//离开窗口}right++;}return len == INT_MAX ? 0 : len;}
};

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

3. 无重复字符的最长子串 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/

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

其实滑动窗口类题目最重要的是弄清楚『 为什么』要使用滑动窗口,而不是『 怎样』适用滑动窗口。

像本题,你是如何分析出要使用滑动窗口的呢?

首先依据暴力枚举的策略,同样固定一个指针,移动另一指针,搭配哈希表得到最长字串:

class Solution {
public:int lengthOfLongestSubstring(string s) {int ret = 0; // 记录结果int n = s.length();// 1. 枚举从不同位置开始的最⻓重复⼦串// 枚举起始位置for (int i = 0; i < n; i++){// 创建⼀个哈希表,统计频次int hash[128] = { 0 };// 寻找结束为⽌for (int j = i; j < n; j++){hash[s[j]]++; // 统计字符出现的频次if (hash[s[j]] > 1) // 如果出现重复的break;// 如果没有重复,就更新 retret = max(ret, j - i + 1);}}// 2. 返回结果return ret;}
};

注意:因为题目说明都为字符,所以我们可以创建一个128大小的数组用来模拟哈希表,没有必要真的申请一个哈希表出来。 

然后才能依据这一暴力枚举的底子我们做优化。

思路:

当right指向重复字符时,我们是否需要直接让right回退,left++呢?

其实如果right指向重复字符了,那么就证明此时就是left开头代表的窗口的最长字串了(因为在这之前right没有指向重复字符),所以此时不需要移动right,而应该移动left直到没有重复字符为止,然后再移动right即可。

  • 如果这个字符出现的频次超过1 ,说明窗口内有重复元素,那么就从左侧开始划出窗口,直到这个元素的频次变为1,然后再更新结果。
  • 如果没有超过1 ,说明当前窗口没有重复元素,可以直接更新结果。

所以『 更新结果』我们可以统一放在『 判断』的外面。

 有了思路,画图独立完成代码,不要直接看博主的代码。

class Solution {
public:int lengthOfLongestSubstring(string s) {int hash[128]={0};int left=0,right=0,len=0;int n=s.size();while(right<n){hash[s[right]]++;//进入窗口while(hash[s[right]]>1)//判断hash[s[left++]]--;//离开窗口len=max(len,right-left+1);//更新结果right++;}return len;}
};

3.最大连续1的个数Ⅲ

1004. 最大连续1的个数 III - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/max-consecutive-ones-iii/description/

给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。

 虽然题目中说是要翻转数字,但我们要的最终结果与翻转无关,何况如果真的实现翻转反而变得复杂,所以这里我们没有必要真的翻转。

仔细阅读题目,其实就是求数组中⼀段最长的连续区间,要求这段区间内 0 的个数不超过 k 个。

既然是连续区间,可以考虑使用『 滑动窗口』来解决问题。

思路:

设置一个 0 计数器 zero。

如果 right 遇到 0,我们应该让 zero ++ ,如果 right 遇到 1,直接跳过即可,这就是『 进入窗口』。

判断什么呢?当然是『 判断』zero是否超过 k,如果超过 就『 离开窗口』,每轮『 更新结果』。

 有了思路,画图独立完成代码,不要直接看博主的代码。

class Solution {
public:int longestOnes(vector<int>& nums, int k) {int left=0,right=0,zero=0;int n=nums.size();int ret=0;while(right<n){if(nums[right]==0)//进入窗口zero++;while(zero>k)//判断{if(nums[left++]==0)//离开窗口zero--;}ret=max(ret,right-left+1);//更新结果right++;}return ret;}
};


4.将 x 减到 0 的最小操作数(medium)

1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/description/

给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。

如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。

阅读题目后,我们发现解决方案可能比较复杂,因为既有可能从左面,也有可能从右面,还有可能一左一右等等,这么多复杂的情况,所以我们需要尝试对问题做转化,这也就是『 正难则反』的思路。 

如上图,我们可以求 target 这一区域最长时,那么此时就对应着最小操作数,最小操作数就等于数组元素个数减去target区域的元素个数。

所以我们成功转化出『 滑动窗口』问题。

  • 如果 sum < target ,右移右指针,直至变量和大于等于 target ,或右指针已经移到头;
  • 如果 sum > target ,右移左指针,直至变量和小于等于 target ,或左指针已经移到头;
  • 如果经过前两步的左右移动使得 sum == target ,维护满足条件数组的最大长度,并让下个元素进入窗口;

 有了思路,画图独立完成代码,不要直接看博主的代码。

class Solution {
public:int minOperations(vector<int>& nums, int x) {int sum=0;for(int a : nums){sum+=a;}int target = sum-x;if(target<0) return -1;//处理细节int left=0,right=0,tmp=0;int n=nums.size();int len=-1;while(right<n){tmp+=nums[right];//进入窗口while(tmp > target)//判断tmp-=nums[left++];//离开窗口if(tmp==target)len=max(len,right-left+1);//更新结果right++;}if(len==-1) return len;else return n-len;}
};

=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

=========================================================================

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

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

相关文章

从MobileNetv1到MobileNetv3模型详解

简言 MobileNet系列包括V1、V2和V3&#xff0c;专注于轻量级神经网络。MobileNetV1采用深度可分离卷积&#xff0c;MobileNetV2引入倒残差模块&#xff0c;提高准确性。MobileNetV3引入更多设计元素&#xff0c;如可变形卷积和Squeeze-and-Excitation模块&#xff0c;平衡计算…

MyBatis完成单表的CRUD

提示&#xff1a;如果没有基础的可以看我的博客 > MyBatis概述与MyBatis入门程序 MyBatis完成单表的CRUD 一、准备工作二、Insert&#xff08;Create&#xff09;1.使用 map 的方式插入数据&#xff08;1&#xff09;编写 SQL 语句&#xff08;2&#xff09;编写测试代码&am…

【STM32 CubeMX】SPI HAL库编程

文章目录 前言一、CubeMX配置SPI Flash二、SPI HAL编程2.1 查询方式函数2.2 使用中断方式2.3 DMA方式 总结 前言 STM32 CubeMX 是一款由 STMicroelectronics 提供的图形化配置工具&#xff0c;用于生成 STM32 微控制器的初始化代码和项目框架。在 STM32 开发中&#xff0c;使用…

4核8G云服务器多少钱?价格汇总

4核8G云服务器多少钱一年&#xff1f;阿里云ECS服务器u1价格955.58元一年&#xff0c;腾讯云轻量4核8G12M带宽价格是646元15个月&#xff0c;阿腾云atengyun.com整理4核8G云服务器价格表&#xff0c;包括一年费用和1个月收费明细&#xff1a; 云服务器4核8G配置收费价格 阿里…

#11vue3中使用el-dialog展示与关闭交由父组件控制的写法

目录 1、法一&#xff1a;通过defineEmits调用父组件方法 1.1、父组件 1.2、子组件&#xff08;CONTENT&#xff09; 2、法二&#xff1a;通过difineExpose暴露子组件属性 2.1、父组件 2.2、子组件&#xff08;Child&#xff09; 1、法一&#xff1a;通过defineEmits调用…

使用 Coze 搭建 TiDB 助手

导读 本文介绍了使用 Coze 平台搭建 TiDB 文档助手的过程。通过比较不同 AI Bot 平台&#xff0c;突出了 Coze 在插件能力和易用性方面的优势。文章深入讨论了实现原理&#xff0c;包括知识库、function call、embedding 模型等关键概念&#xff0c;最后成功演示了如何在 Coze…

关于Windows中的DirectX的知识,看这篇文章就差不多了

DirectX是Windows中用于多媒体和视频程序的API集合,对游戏玩家尤其重要。DirectX诊断工具显示有关DirectX的丰富信息,还允许你在DirectX系统上执行基本诊断测试。如果你想检查你正在运行的DirectX版本,甚至输出一个充满诊断信息的文件以进行故障排除,下面是如何做到的。 D…

开发知识点-JAVA-springboot+Spring Security/Shiro

Spring Security/Shiro shiroShiro反序列化相关URLDNS链Shiro CC链Shiro CB链Shiro反序列化WAF绕过Java快速开发框架_若依——前后端分离版- 3. 登陆 springsecurity认证 Debug - postman模拟SpringBoot+SpringSecurity+dubbo图书电商后台实战-对象映射-基本属性映射SpringBoot…

一连三部电影撤出春节档,给行业带来什么启示?

继《我们一起摇太阳》后&#xff0c;《红毯先生》于2月16日晚也宣布退出今年春节档。 至此&#xff0c;加上动画电影《黄貔&#xff1a;天降财神猫》&#xff0c;2024年春节档已有三部影片撤档&#xff0c;在春节档历届过往中实属少见。 其中&#xff0c;《红毯先生》、《我们…

【数据仓库】主题域和数据域

数据域与主题域区别 https://www.cnblogs.com/datadance/p/16898254.html 数据域是自下而上&#xff0c;以业务数据视角来划分数据&#xff0c;一般进行完业务系统数据调研之后就可以进行数据域的划分。针对公共明细层&#xff08;DWD&#xff09;进行主题划分。主题域则自上而…

《苍穹外卖》知识梳理6-缓存商品,购物车功能

苍穹外卖实操笔记六—缓存商品&#xff0c;购物车功能 一.缓存菜品 可以使用redis进行缓存&#xff1b;另外&#xff0c;在实现缓存套餐时可以使用spring cache提高开发效率&#xff1b;   通过缓存数据&#xff0c;降低访问数据库的次数&#xff1b; 使用的缓存逻辑&#…

ChatGPT的大致原理

国外有个博主写了一篇博文&#xff0c;名字叫TChatGPT: Explained to KidsQ」&#xff0c; 直译过来就是&#xff0c;给小孩子解释什么是ChatGPT。 因为现实是很多的小孩子已经可以用父母的手机版ChatGPT玩了 &#xff0c;ChatGPT几乎可以算得上无所不知&#xff0c;起码给小孩…

CDH 6.3.2集成Hudi异常org.codehaus.jackson不存在及开源JDK版本异常

CDH 6.3.2集成Hudi异常&#xff0c;首先获取hudi源码&#xff0c;地址&#xff1a;git clone https://github.com/apache/hudi.git&#xff0c;进入根目录hudi编译相关jar时&#xff0c;存在2个问题jar包依赖为导入和开源JDK版本问题。异常分别如下所示。 1.编译命令 到hudi根…

【漏洞复现-通达OA】通达OA share身份认证绕过漏洞

一、漏洞简介 通达OA(Office Anywhere网络智能办公系统)是中国通达公司的一套协同办公自动化软件。通达OA /share/handle.php存在一个认证绕过漏洞,利用该漏洞可以实现任意用户登录。攻击者可以通过构造恶意攻击代码,成功登录系统管理员账户,继而在系统后台上传恶意文件控…

哪种台灯的灯光适合学生用?明基/书客/松下等护眼台灯推荐

目前近视人群越来越多&#xff0c;并且有低龄化的倾向。针对护眼这一卖点&#xff0c;市面上出现了很多护眼台灯品牌&#xff0c;但是很多不知名的网红品牌生产出来的产品质量没有办法得到保障。在挑选护眼台灯时&#xff0c;还是要先做好攻略才不会踩雷。 一、使用护眼台灯更…

Stable Diffusion webui安装详细教程

上一篇文章介绍了sd主流的ui&#xff0c;相信大家已经有所了解&#xff0c;下面为大家介绍sd-webui的安装详细教程 文章目录 一、 安装包说明二、对电脑的要求三、安装文件介绍四、安装步骤五、电脑问题与云主机六、界面简要说明及通用反向提示词 一、 安装包说明 通常我们使…

14. Qt 程序菜单实现,基于QMainWindow

目录 前言&#xff1a; 技能&#xff1a; 内容&#xff1a; 一、ui中直接添加控件实现 二、 完全通过代码实现菜单 参考&#xff1a; 前言&#xff1a; 基于QMainWindow&#xff0c;两种方式实现菜单&#xff1a;通过直接添加ui控件快速添加菜单和完全通过代码实现菜单&a…

护眼落地灯值得买吗?书客、霍尼韦尔、柏曼三款落地灯大PK!

落地灯对于上班族、学生党来说真的很友好&#xff0c;能够提供贴合眼睛用光舒适的光度&#xff0c;使这些日常长时间用眼的人能够减少不良光线对眼睛造成的影响&#xff0c;从而科学健康的用眼&#xff01; 市面上的落地灯产品越来越多&#xff0c;琳琅满目的产品让不少刚接触落…

⭐北邮复试刷题429. N 叉树的层序遍历(按层入队出队BFS)(力扣每日一题)

429. N 叉树的层序遍历 给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&#xff09;。 示例 1&#xff1a;输入&a…

自定义类型详解 ----结构体,位段,枚举,联合

目录 结构体 1.不完全声明 2.结构体的自引用 3.定义与初始化 4.结构体内存对齐与结构体类型的大小 结构体嵌套问题 位段 1.什么是位段&#xff1f; 2.位段的内存分配 枚举 1.枚举类型的定义 2.枚举的优点 联合&#xff08;共同体&#xff09; 1.联合体类型的声明以…