基础算法---滑动窗口

文章目录

  • 什么是滑动窗口
  • 1.长度最小的子数组
  • 2.无重复字符的最长子串
  • 3.最大连续1的个数
  • 4.将x减到0的最小操作数
  • 5.最小覆盖子串
  • 总结

在这里插入图片描述

什么是滑动窗口

滑动窗口(Sliding Window)是一种在计算机科学中用于解决各种子数组或子字符串问题的技术。滑动窗口技术通过维护一个固定大小的窗口在数组或字符串上移动,从而使得可以在较短的时间内解决一些复杂的问题。这种方法在处理一系列数据时特别高效。滑动窗口(Sliding Window)是一种在计算机科学中用于解决各种子数组或子字符串问题的技术。滑动窗口技术通过维护一个固定大小的窗口在数组或字符串上移动,从而使得可以在较短的时间内解决一些复杂的问题。这种方法在处理一系列数据时特别高效。
在这里插入图片描述
滑动窗口其实可以理解为一个左指针和一个右指针共同维护的一个区间,然后一起移动,这个区间的长度可能是不变的,也可能是变化的。
滑动窗口的几个基本步骤:
1.进窗口
2.判断是否出窗口
3.更新结果
接下来我们用几道题来演示滑动窗口这个算法。

1.长度最小的子数组

题目链接
题目:

在这里插入图片描述

样例输入和输出:

在这里插入图片描述

这道题的意思就是让我们求数组中和为target或者大于target的长度最小的子数组。首先我们来看看示例1:
在这里插入图片描述

从下图可以直观的看见最后一个子数组是最短的,所以这里输出是2,理解了题意接下来我们来想想怎么解。
解法一:暴力解法
暴力解法很容易想到,我们用两层循环将所有情况全部遍历一遍,然后用一个长度len来记录每次循环的最小的结果,然后最后遍历完了之后返回结果。
解法二:滑动窗口
暴力枚举的优化算法
在这里插入图片描述
我们看1,当我们遍历到1的情况的时候,按照暴力解法,先left指针后移,然后将right指针移到left指针重新遍历一遍即可,但是我们想一想有没有必要将right指针移到left的位置重新遍历,首先left指针向后移动一个位置之后只会出现两种情况,第一种情况:满足条件大于等于target,大于等于target而且长度还比前一个长度短,所以这里可以直接更新结果,没必要将right移到left重新遍历,来看第二种情况,,就是left向后移动以后不满足条件,不满足条件了,那将right移动到left重新遍历到未移动的位置都不满足,所以这里更不用重新遍历,所以综上两种情况,都不需要将right移到left的位置重新遍历。所以这里我们满足情况只需要将left++,right不需要移到left重新遍历,每次left移动之后还是要判断一下是否满足条件,满足条件则更新结果。
所以这里很快就出来了:
步骤就是1.进窗口 2.判断是否出窗口,更新结果
代码展示:

class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {int left = 0,right=0;int sum=0,len=INT_MAX;//len取最大,因为len最后求的是minwhile (right < nums.size()){//进窗口sum+=nums[right];//循环判断while(sum>=target){len=min(len,right-left+1);//更新结果sum-=nums[left++];//出窗口}right++;}return len==INT_MAX?0:len;
}
};

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

题目链接
题目:

样例输入和输出:

在这里插入图片描述

这道题题目意思很简单,,就是让我们求无重复字符的子串,并且还是最长的。

解法一:
暴力解法,暴力解法很简单,把这个字符串给遍历一遍,然后将所有的子串的情况全部求出来,每次求出一种判断一下,这里判断我们就用hash表,看看子串中字符的种类,如果每个种类只有一种说明这个子串是符合要求的,如果hash表中有一个字符是有多个的,说明这个子串是不满足的。最后返回满足的最长的子串即可。
解法二:滑动窗口+hash
在这里插入图片描述

首先我们还是需要用到hash表,用来记录区间内的字符的种类,但是暴力解法是逐个遍历,优化的滑动窗口当我们遍历到第一种情况的时候right指针继续向后移动。
在这里插入图片描述
这里这个滑动窗口已经不满足条件了所以这里我们应该让left++,left++之后right还有没有必要向前移动,很显然是没必要的,因为和上一道题相似,这里无非就是两种情况:
1.left移动之后这个区间不成立,这个区间都不成立了right还从前往后遍历是不是多余?
2.left移动之后这个区间成立了,这个区间成立,但是和前一个区间是相同长度的区间,所以向前遍历的长度都没有这个区间长,所以更不需要向前遍历。
综上right只需要向后移动,不需要向前移动。

细节:每次我们入窗口的时候都需要判断一下hash表中的字符种类的个数是否只有一个,如果有多个的话则移动left然后将hash表中的元素进行–。直到减到1个为止。然后再更新结果。

代码展示:

class Solution {
public:int lengthOfLongestSubstring(string s) {//创建一个hash数组用来记录重复字母的个数int hash[128]={0};int left=0,right=0;int len=0;int n=s.size();while(right<n){hash[s[right]]++;while(hash[s[right]]>1){hash[s[left]]--;left++;}len=max(len,right-left+1);right++;}return len;}
};

3.最大连续1的个数

题目链接
题目:

在这里插入图片描述

样例输入和输出:

在这里插入图片描述

这道题大致的意思就是我们需要找到连续的1的个数最大的子数组,并且我们可以将0翻转成1。
在这里插入图片描述
对于第一个例子来说,由于我们可以将0翻转成1,所以第一个区间是最长的,第二个区间和第三个区间是一样长的,但是比第一个区间长,所以我们可以返回最长的区间长度。

解法一:暴力解法
暴力解法也只需要暴力枚举,枚举出所有的情况,但是我们这道题需要正难则反,因为如果我们真的翻转每一个零的话,这道题是很难的,这道题要我们求最长的连续的1的区间,我们可以转换为求最长的连续1的区间并且如果这个区间涵盖0的话,零的个数不能超过k个,如果这个区间的0的个数不超过k个那么这个区间就是合法的。转换了之后就很好做了,没枚举一个把这个数放进hash表,然后判断其零的个数,如果零的个数是合法的,那么这个区间就成立,则更新最长结果。
解法二:滑动窗口+hash表
这道题转换了之后就和上一道一个样了,我们只需要用一个两个空间的hash表来记录这里面1和0的个数即可,每次入完窗口之后,都判断一下这个窗口是否合法,也就是判断一下这个窗口内的0的个数是否大于k个了,如果没有大于k个,则继续,更新结果。

代码展示:

class Solution {
public:
int longestOnes(vector<int>& nums, int k) 
{//定义左右指针int left = 0, right = 0;//定义长度并且定义长度int len = 0, n = nums.size();//定义1的个数和0的个数int arr[2]={0};while (right < n){//入窗口arr[nums[right]]++;//判断窗口内的零的个数,如果零大于k的时候就left++,并且出窗口while(arr[0]>k){arr[nums[left]]--;left++;}//判断完了之后更新长度len = max(len, right - left + 1);//更新rightright++;}//返回最大长度return len;
}
};

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

题目链接
题目:

在这里插入图片描述

样例输入和输出:

在这里插入图片描述

这道题的大致意思我们每次只能选最左边或者最右边的数,然后每次选了这个数之后,这个数就被删除了,不能选这个数,最后选了数我们要选出最少的数使得能将x减为零的长度。大致就是这个意思。

这道题要是我们直接做的话,会相当难,我们可以换个角度来看这个道题,这道题其实就是让我们求左右两个不连续的区间的和为x,我们用第一个例子来看:
在这里插入图片描述
这样转换之后这道题的难度瞬间降低了一个层次。
解法一:
暴力枚举,暴力枚举每种情况,这里我们初始化需要将len初始化为-1,如果最后len等于-1,则返回len,如果最后len不是-1,则返回的是nums的长度-len,暴力枚举每种情况,然后求出最长的那个。

解法二:
滑动窗口,这里步骤我们就不讲了,我们讲一下细节的,出窗口的条件,当我们用一个sum记录和的时候,发现这个和大于的时候就开始出窗口。
代码展示;

class Solution {
public:int minOperations(vector<int>& nums, int x) {int sum=0;for(auto e:nums)sum+=e;int target=sum-x;//细节问题if(target<0)return -1;int ret=-1;for(int left=0,right=0,tmp=0;right<nums.size();right++){//进窗口tmp+=nums[right];//判断出窗口while(tmp>target){tmp-=nums[left++];}if(tmp==target){ret=max(ret,right-left+1);}}if(ret==-1)return ret;elsereturn nums.size()-ret;}
};

5.最小覆盖子串

题目链接
题目

在这里插入图片描述

样例输入和输出;

在这里插入图片描述

这道题题目意思也很简单,我们需要找到一个子串,这个子串满足在s中可以有重复的字符,但是不能少字符,意思就是s中的子串的字符的种类大于等于t中的字符种类,字符的个数也是大于等于t中的字符个数。

解法一:暴力枚举+hash表
首先我们暴力枚举出每种情况,然后再利用两个hash表,先将t中的字符存在hash表中,然后在暴力枚举的过程中,我们每入一个窗口,都需要判断其窗口内的字符种类,然后暴力枚举出满足的情况之后取子串,返回其子串。
解法二:滑动窗口+hash表
入窗口什么的还是和前面讲的一样,但是唯一有一个区别是这里是满足条件擦开始出窗口,
在这里插入图片描述
这里蓝色窗口的区间满足了条件,我们开始出窗口,出窗口有两种可能,就是还满足条件,还有一种是不满足条件,如果还满足条件则更新最小的结果,如果不满足了,继续入窗口,所以这里我们更新结果的地方应该在出窗口之前,这里我们需要用一个变量记录有效字符的个数,首先我们先用一个变量kinds来记录t中的字符的种类,然后再用count记录区间中有效字符的个数,在记录窗口中有效字符的个数的时候,我们只需要判断一下这个字符是否存在于t中即可,如果存在于t中则为有效字符,并且这里如果t中a有1个,s中a有很多个,这里我们只记录一次有效数据。

代码展示:

class Solution {
public:
string minWindow(string s, string t)
{int hash1[128] = { 0 }, hash2[128] = { 0 };int left = 0, right = 0;int kinds = 0;//统计有效字符的个数for (auto e : t){if (hash1[e] == 0)kinds++;//统计表中的字符hash1[e]++;}int count = 0;int minlen = INT_MAX;int begin = -1;while (right < s.size()){hash2[s[right]]++;if (hash2[s[right]] == hash1[s[right]]){count++;}while (count == kinds){if (right - left + 1 < minlen){minlen = right - left + 1;begin = left;}if (hash1[s[left]] == hash2[s[left]]){count--;}hash2[s[left]]--;left++;}right++;}if (begin == -1)return "";else return s.substr(begin, minlen);
}
};

总结

滑动窗口算法是一种高效且灵活的技术,它可以显著减少解决某些问题的时间复杂度。在处理数组和字符串相关的问题时,滑动窗口尤其有效,它通过动态调整窗口的大小来满足特定的条件,避免了不必要的重复计算。

在本文中,我们详细讨论了滑动窗口的基本概念和应用场景,并通过具体的例子展示了如何使用滑动窗口解决无重复字符的最长子串问题。通过这些示例,我们可以看到滑动窗口的强大之处,以及在实际编程中如何灵活应用这项技术。

希望这篇文章能帮助你更好地理解滑动窗口算法,并在以后的算法学习和实践中熟练应用这项技术。如果你有任何疑问或新的想法,欢迎在评论区留言,我们一起讨论交流。感谢阅读!

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

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

相关文章

【SQL每日一练】HackerRan-Basic Join-Challenges练习

文章目录 题目题析题解1.sqlserver 题目 编写一个查询来打印 hacker _ id、 name 和每个学生创建的挑战的总数。按照挑战的总数按降序对结果进行排序。如果不止一个学生创建了相同数量的挑战&#xff0c;那么按 hacker _ id 对结果进行排序。如果不止一个学生创建了相同数量的…

北京BJ90升级新款迈巴赫大连屏四座头等舱行政四座马鞍

北京BJ90升级奔驰迈巴赫头等舱行政四座大联屏的内饰效果会非常出色&#xff0c;将为车辆带来更豪华、高端的内饰氛围。以下是升级后可能的效果&#xff1a; • 科技感提升&#xff1a;奔驰的中控系统一直以来都以其先进的科技和用户友好的界面而闻名。升级后&#xff0c;北京B…

Windows Api如何创建一个快捷方式并且在开始菜单搜索到自己的应用

原文链接&#xff1a;http://cshelloworld.com/home/detail/1804473083243925504 当我们点击win10系统搜索框的时候&#xff0c;输入名称 &#xff0c;win10会帮助我们匹配到对应的应用。这里搜索框实际上就是windows系统的开始菜单。 接下来我们随便找一个应用&#xff0c;右…

湖北民族大学2024年成人高等继续教育招生简章

湖北民族大学&#xff0c;这所承载着深厚文化底蕴和卓越教育理念的学府&#xff0c;在崭新的2024年再次敞开怀抱&#xff0c;热烈欢迎有志于深化学习、提升自我的成人学员们。今年的成人高等继续教育招生&#xff0c;不仅是学校对于终身教育理念的具体实践&#xff0c;更是为广…

每日签到页面模板组件,简单好用,用了会上瘾的那种

uni-app 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;开发者编写一套代码&#xff0c;可发布到iOS、Android、Web&#xff08;响应式&#xff09;、以及各种小程序&#xff08;微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝&#xff09;、快应用等多个平台。 今日给…

机器学习算法(二):1 逻辑回归的从零实现(普通实现+多项式特征实现非线性分类+正则化实现三个版本)

文章目录 前言一、普通实现1 数据集准备2 逻辑回归模型3 损失函数4 计算损失函数的梯度5 梯度下降算法6 训练模型二、多项式特征实现非线性分类1 数据准备与多项式特征构造2 逻辑回归模型三、逻辑回归 --- 正则化实现1 数据准备2 逻辑回归模型3 正则化损失函数4 计算损失函数的…

前端下载文件流,axios设置responseType: arraybuffer/blob无效

项目中调用后端下载文件接口&#xff0c;设置responseType: arraybuffer,实际拿到的数据data是字符串 axios({method: post,url: /api/v1/records/recording-file/play,// 如果有需要发送的数据&#xff0c;可以放在这里data: { uuid: 06e7075d-4ce0-476f-88cb-87fb0a1b4844 }…

图像编辑技术的新篇章:基于扩散模型的综述

在人工智能的浪潮中&#xff0c;图像编辑技术正经历着前所未有的变革。随着数字媒体、广告、娱乐和科学研究等领域对高质量图像编辑需求的不断增长&#xff0c;传统的图像编辑方法已逐渐无法满足日益复杂的视觉内容创作需求。尤其是在AI生成内容&#xff08;AIGC&#xff09;的…

CPP-类对象大小的组成

要计算一个类对象的大小要先明白一个问题&#xff1a;类中既可以有成员变量&#xff0c;又可以有成员函数&#xff0c;那么一个类的对象中包含了什么&#xff1f; 下面来看一段代码&#xff1a; // 类中既有成员变量&#xff0c;又有成员函数 class A1 { public:void f1() {} …

快速生成基于vue-element的后台管理框架,实现短时间二次开发

你是否遇到过当你想要独立开发一个项目时对反复造轮子的烦扰&#xff1f; 这种流水线的操作实在让人受不了 而vue-element-template很好的帮你解决了这个烦恼 只需克隆下来&#xff0c;改改图标&#xff0c;模块名&#xff0c;甚至样式&#xff0c;就会变成一个全新的自己的项目…

轻松恢复丢失数据EasyRecovery你的数据守护神

数据丢失&#xff1f;别怕&#xff01;EasyRecovery来帮忙 大家好呀&#xff0c;今天我要分享一个我超级喜欢的数据恢复软件——EasyRecovery&#xff01;&#x1f389; 如果你也经历过误删文件、硬盘格式化或是意外丢失重要数据的尴尬和焦虑&#xff0c;那你一定要看看这个神器…

uniapp 微信小程序更改轮播图指示点

仅微信小程序有效 /* #ifdef MP-WEIXIN */// 默认指示点样式wx-swiper .wx-swiper-dot {position: relative;background-color: #ffffff;width: 28rpx;border-radius: 10rpx;height: 8rpx;opacity: 0.4;}// 当前选中样式wx-swiper .wx-swiper-dot-active {background-color: #f…

HTML静态网页成品作业(HTML+CSS)——家乡泉州介绍网页(3个页面)(表格布局)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;table布局&#xff0c;未使用Javacsript代码&#xff0c;共有3个页面。…

HarmonyOS父子组件传递参数

HarmonyOS父子组件传递参数 1. 使用State和Prop进行父子组件传递———注意是单向同步 Prop装饰器&#xff1a;父子单向同步 注意&#xff1a;只支持单向同步&#xff0c;同时也只能支持string\number\boolean\enum比较简单的类型。 代码 // 使用 props 进行父子组件传值…

Python爬虫介绍

Python 作为一种广泛应用的编程语言&#xff0c;在 Web 开发、大数据开发、人工智能开发和嵌入式开发等领域都有着重要的应用。 Python 的易学性、清晰性和可移植性等特点使它得到很多技术人士的喜爱。对于数据科学和机器学习领域的程序员来说&#xff0c;Python 提供了强大的…

朴素贝叶斯案例

一、朴素贝叶斯算法&#xff1a; 朴素贝叶斯算法&#xff0c;是一种基于贝叶斯定理与特征条件独立假设的分类方法&#xff0c;基于贝叶斯后验概率建立的模型&#xff0c;它用于解决分类问题。朴素&#xff1a;特征条件独立&#xff1b;贝叶斯&#xff1a;基于贝叶斯定理。属于…

【Python】已解决:ModuleNotFoundError: No module named ‘paddle’

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;ModuleNotFoundError: No module named ‘paddle’ 一、分析问题背景 在Python编程中&#xff0c;ModuleNotFoundError是一个常见的错误&#xff0c;它通常发生…

C语言中的进制转换

基础概念 进制又称数制&#xff0c;是指用一组固定的符号和统一的规则来表示数值的方法&#xff0c;在C语言中&#xff0c;可以使用不同的前缀来表示不同的进制&#xff1a; 二进制&#xff1a;以0b或0B为前缀&#xff08;部分编译器可能不支持&#xff09;八进制&#xff1a…

【论文精读】分类扩散模型:重振密度比估计(Revitalizing Density Ratio Estimation)

文章目录 一、文章概览&#xff08;一&#xff09;问题的提出&#xff08;二&#xff09;文章工作 二、理论背景&#xff08;一&#xff09;密度比估计DRE&#xff08;二&#xff09;去噪扩散模型 三、方法&#xff08;一&#xff09;推导分类和去噪之间的关系&#xff08;二&a…

LVGL8.3动画图像(太空人)

LVGL8.3 动画图像 1. 动画图像本质 我们知道电影属于视频&#xff0c;而电影的本质是将一系列动作的静态图像进行快速切换而呈现出动画的形式&#xff0c;也就是说动画本质是一系列照片。所以 lvgl 依照这样的思想而定义了动画图像&#xff0c;所以在 lvgl 中动画图像类似于普…