基础算法---滑动窗口

news2025/2/24 5:58:55

文章目录

  • 什么是滑动窗口
  • 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最后求的是min
    while (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);
        //更新right
        right++;
    }
    //返回最大长度
    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;
        else
        return 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.coloradmin.cn/o/1842289.html

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

相关文章

如何建立私域流量?私域流量怎么运营,一文读懂

当全网都在讨论私域流量&#xff0c;你是不是也有很多问号呢&#xff1f; 互联网高速发达&#xff0c;消费形式日新月异&#xff0c;跟不上时代就会被时代淘汰&#xff0c;接下来&#xff0c;我们就从3个层面深度讨论下私域流量究竟是什么&#xff1f;为什么要玩转私域流量&am…

详细解析Ubuntu22 部署Kaldi大模型

一、下载Kaldi模型 下载地址&#xff1a;GitHub - kaldi-asr/kaldi: kaldi-asr/kaldi is the official location of the Kaldi project. 下载文件解释&#xff1a; 一般常用的是src、tools和egs包 src&#xff08;源代码&#xff09;包&#xff1a; 包含Kaldi的核心源代码&…

Flutter调用本地web

前言: 在目前Flutter 环境中&#xff0c;使用在线 webview 是一种很常见的行为 而在 app 环境中&#xff0c;离线使用则更有必要 1.环境准备 将依赖导入 2.引入前端代码 前端代码有两种情况 一种是使用打包工具 build 而来的前端代码 另一种情况是直接使用 HTML 文件 …

Quantlab整合Alpha158因子集,为机器学习大类资产配置策略做准备(代码+数据)

原创文章第565篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 我们的研报得现工作&#xff0c;用了两篇文章讲数据准备&#xff1a; 【研报复现】年化16.19%&#xff0c;人工智能多因子大类资产配置策略 【研报复现】年化27.1%&#xff0c;人…

vmware workstation下centos7屏幕切换及大小调整

虚拟机版本&#xff1a;vmware workstation15.5.2 操作系统版本&#xff1a;centos 7.9.2009 一 图形界面和命令行界面切换方法 在CentOS 7中&#xff0c;可以使用以下方法切换界面&#xff1a; 1 使用快捷键切换&#xff1a;按下Ctrl Alt F2&#xff08;或F3&#xff0…

0.5 逐行扫描(Progressive scan)简介

0.5 逐行扫描简介 逐行扫描&#xff08;Progressive scan&#xff09;是一种将图像显示在扫描式的显示设备上的方法。 逐行扫描常被用在计算机显示器上。 逐行扫描按照从左到右&#xff0c;从上到下的顺序扫描图像的所有行。如下图&#xff1a; 下图粗略的将逐行扫描与隔行…

LORA、UNB无线网关物联网锁助力人才公寓智慧化管理

吸引和留住青年人才是城市持续发展的关键&#xff0c;解决青年人才住房问题又是其中重要一环。“人才跟着产业走、公寓跟着人才建”已成为全国各地新建及改造人才公寓的目标&#xff0c;“引才聚才”离不开人才公寓行业布局与发展。 人才公寓不同于普通的长短租公寓&#xff0c…

[HGAME 2022 week1]Matryoshka(古典密码混合)

题目&#xff1a; 直接说方法&#xff1a; 首先这是一段盲文&#xff0c;要先将盲文反转&#xff0c; 然后再用摩斯密码转换 将得到的字符串去掉“,”后&#xff0c;base16解码 在尝试维吉尼亚密码 再用base64解码 然后用凯撒密码 最后栅栏密码&#xff08;22栏&#xff09;

专家观点∣企企通采购供应链数字化总监于海生:如何利用数字化技术重构采购流程,推动企业降本增效?

摘要 数字化转型现已成为企业提升竞争力、实现降本增效的必由之路。企业应主动参与到数字经济的建设中&#xff0c;以数据资源为关键要素&#xff0c;以现代信息网络为主要载体&#xff0c;以信息通信技术的有效使用作为效率提升和经济结构优化的重要推动力的一系列经济活动&a…

基于STC12C5A60S2系列1T 8051单片机接收串口调试助手发送的固定长度字符串控制单片机的功能

基于STC12C5A60S2系列1T 8051单片机接收串口调试助手发送的固定长度字符串控制单片机的功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机串口通信介绍STC12C5A60S2系列1T 8051单片机串口通信的结构基于STC12C5A60S2系列1T 8051单片机串口通信的特殊功能…

广州化工厂可燃气体报警器检定检验:安全生产新举措显成效

随着科技的不断发展&#xff0c;可燃气体报警器的检定检验技术也在不断进步。 广州的一些化工厂开始采用先进的智能检测系统和数据分析技术&#xff0c;对报警器的性能进行更加精准和全面的评估。 这些新技术不仅能够提高检定检验的效率和准确性&#xff0c;还能够为化工厂的…

第11章 测试代码

第11章 测试代码 11.1 测试函数11.1.1 单元测试和测试用例11.1.2 可通过的测试11.1.3 未通过的测试11.1.4 测试未通过时怎么办11.1.5 添加新测试 11.2 测试类11.2.1 各种断言方法11.2.2 一个要测试的类11.2.3 测试 AnonymousSurvey 类11.2.4 11.1 测试函数 11.1.1 单元测试和测…

Rancher注册已有k8s集群

Rancher安装后注册K8s集群操作 1.Rancher安装 编辑docker—compose文件 version: 3.8services:rancher:image: registry.cn-hangzhou.aliyuncs.com/rancher-images/rancher:v2.8.5container_name: rancherprivileged: truerestart: unless-stoppedports:- "18080:80&qu…

2004年上半年软件设计师【下午题】试题及答案

文章目录 2004年上半年软件设计师下午题--试题2004年上半年软件设计师下午题--答案2004年上半年软件设计师下午题–试题

Ant Design Vue中的Table和Tag的基础应用

目录 一、Table表格 1.1、显示表格 1.2、列内容过长省略展示 1.3、完整分页 1.4、表头列颜色设置 二、Tag标签 2.1、根据条件显示不同颜色 2.2、控制关闭事件 一、Table表格 效果展示&#xff1a; 官网&#xff1a;Ant Design Vue 1.1、显示表格 <a-tableref&quo…

Simufact Additive仿真助力金属粘结剂喷射成型(MBJ)工业化

引 言 烧结过程中“设计”补偿变形的能力被视为是实现金属粘结剂喷射成型&#xff08;MBJ&#xff09;快速商业化的关键。针对烧结过程的仿真分析&#xff0c;Simufact Additive软件现已推出了MBJ仿真模块第三个版本&#xff0c;当前版本能够准确模拟烧结过程&#xff0c;预测…

微信多开器

由于微信的限制&#xff0c;我们平时只能登录一个微信&#xff0c;要登录多个微信一般需要多台手机&#xff0c;很显然这种方法很费手机&#xff01;&#xff01;一个微信多开神器可以给你省下好几台手机钱&#xff0c;抓紧拉下来放手机里落灰http://www.xbydon.online/?p132 …

Windows清理C盘的4类方法【新手小白专用】

一、系统清理法 1.磁盘清理 【Win R】启动命令提示符&#xff0c;输入【cleanmgr】,选择打开C盘&#xff0c;勾选要清理的文件 一般大的文件是【临时文件和下载的程序文件】 2.存储清理&#xff08;1&#xff09; 打开【设置】-【系统】-【存储】-【配置存储感知或立即运行…

Vue elementui表格

去除表头 <el-table:data"tableData"stripestyle"width: 100%":cell-style"{ text-align: justify-all }":show-header"false"></el-table>合并 <template><div class"elife-container"><el-ro…

大模型LLM微调技术进展与热门方法汇总

大模型微调是机器学习中的一项重要技术&#xff0c;旨在帮助我们降低成本&#xff0c;进一步提高模型的性能。具体来说&#xff0c;大模型微调指的是在现有预训练模型的基础上&#xff0c;根据特定任务数据进行微调&#xff0c;以适应任务的特定需求&#xff0c;以便我们更好地…