滑动窗口——优选算法

news2024/9/20 22:12:08

个人主页:敲上瘾-CSDN博客

个人专栏:游戏、数据结构、c语言基础、c++学习、算法

目录

一.滑动窗口算法原理:

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

1.题目解析​编辑

2.算法原理

3.代码编写

三.长度最小的子数组

1.题目解析

2.算法原理

3.代码编写

四.最小覆盖子串

1.题目解析

2.算法原理

3.代码编写

五.总结


一.滑动窗口算法原理:

        滑动窗口可以说是一种特殊双指针算法,即它同样用两个指针实现。滑动窗口:用一个left指针和right指针来维护一段区间即[left, right],也可称为窗口,right右移即进窗口,left右移即出窗口。即通常情况下left和right指针都是同向移动的。对于滑动窗口我们主要关心以下几点:

进窗口,出窗口,更新结果。进窗口肯定是在出窗口前进行的,而什么时候更新结果因题而异。

        其实对于滑动窗口本身还是挺简单的,难点在我们能不能想到使用滑动窗口,接下来我准备了三个题,每题都分为三个步骤:题目解析,算法原理,代码编写。从最普通的暴力解法过渡到滑动窗口。最后来做总结。

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

1.题目解析

        该题需要我们求出字符串s内无重复字符的最长子串,注意这里子串的意思也就是在字符串s内连续的一段字符,所以在求解该题时最好不要对原字符串进行改动。

2.算法原理

        明显这道题很容易想到的就是暴力枚举,但是时间复杂度比较高是过不了该题的测试的。在我们没能想到其他解法时,可以这样做,去分析暴力解法,从暴力解法中找到优化的规律。如下:

按以上方法把整个数组遍历完可以解决这个题目,但可以做以下优化:

        这就是一个滑动窗口,把[left, right]区间当作一个窗口存放的是不重复的子串,然后用一个len变量来记录窗口的最大长度,当right滑动到字符串结尾时也就把所有的情况都记录了一遍,此时结束循环返回len该算法就完成了。

        注意:这里因为要检查字符是否重复所以用一个哈希表来记录窗口内数据出现的个数可以提高效率。

3.代码编写

class Solution 
{
public:
    int lengthOfLongestSubstring(string s) 
    {
        if(s.size()==0) return 0;
        int len=-1;
        int arr[127]={0};
        for(int left=0,right=0;right<s.size();right++)
        {
            arr[s[right]]++;
            cout<<arr[s[right]]<<' ';
            while(arr[s[right]]==2)
            {
                arr[s[left++]]--;
            }
            if(len<right-left+1) len=right-left+1;
        }
        return len;
    }
};

三.长度最小的子数组

1.题目解析

        本题要求子数组(即数组内的一段连续的元素)的元素之和大于等于target的最小长度,如果不存在返回0。例如示例1,[2,3,1,2,4,3]中子数组大于等于target的子数组有:

[2,3,1,2],[2,3,1,2,4],[2,3,1,2,4,3],[3,1,2,4],

[3,2,1,4,3],[1,2,4],[1,2,4,3],[2,4,3],[4,3]。

而长度最小的子数组为[4,3],长度为2,以上所列的子数组是一个模拟暴力枚举的结果

2.算法原理

        该题可以使用暴力枚举(即两个循环解决)时间复杂度为O(N^2)。对于暴力解法在这里就不再多讲,现在我们可以试图从暴力解法中寻找规律并进行优化。如下:

        以上我们分析的结果就是一个滑动窗口算法,left,right来维护这个窗口,left右移即出窗口,right右移即进窗口,当窗口里的元素之和大于等于target时更新最小长度。直到right滑动到数组结尾可得到答案。时间复杂度为O(N)。

3.代码编写

class Solution 
{
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int left=0,right=0;
        int sum=0,len=0;
        while(right<nums.size())
        {
            sum+=nums[right];//进窗口
            while(sum>=target)
            {
                int ln=right-left+1;//计算窗口长度
                if(len==0||len>ln) len=ln;//更新len
                sum-=nums[left++];//出窗口
            }
            right++;
        }
        return len;
    }
};

四.最小覆盖子串

1.题目解析

        题目意思是给一个字符串s和t,要求在字符串s中找一个子串,这个子串要满足两点:(1)涵盖t字符串里的所有字符(包括重复字符),(2)最短的一个子串。注意:这个子串的要求不是涵盖t字符串,而是涵盖t字符串中的所有字符,这两者是有区别的。如示例1到3。

2.算法原理

        同样这题也是可以使用暴力枚举的,我们还是从暴力枚举中去寻找规律并优化。

        分析到此处,我们可以发现解题思路和上题可以说几乎是一模一样,但该题真正的难点并不是在此处。而在于我们如何去判断子串中是否包含t中的所有字符

        因为这里对子串中t的字符并没每有顺序要求,只要个数对上就行了,所以我们很自然地可以想到使用哈希表(此题使用数组充当哈希表更为高效)来记录数据出现个数。具体怎么判断呢?

        使用两个哈希表分别记录t中的字符以及个数和子串(窗口)中字符以及出现个数。然后使用遍历的方式去匹配并判断。这样确实行得通,不过涉及遍历时间复杂度一下子就上来了。在这里我给大家分享一个小技巧,是官方题解上没有的。同样我们用这两个哈希表,但不用遍历去匹配判断,而是使用一个count变量记录子串(窗口)中有效字符的个数

进窗口:当子串中某字符的个数与t字符串中对应字符个数相等时(用哈希表判断),有效字符count++。

更新结果并出窗口:当count等于t中的字符种类数时,判断并更新结果,当出窗口的元素为有效元素时(哈希表判断)count--。

3.代码编写

class Solution
{
public:
    string minWindow(string s, string t)
    {
        string str;//储存最终结果
        if(s.size()<t.size()) return str;
        int hash1[128],hash2[128];
        int len=0;
        for(auto ch:t) if(hash1[ch]++==0) len++;
        int minlen=INT_MAX,begin=-1;//minlen记录最小子串长度,begin记录子串开始的位置
        for(int left=0,right=0,count=0;right<s.size();right++)
        {
            char in=s[right];
            hash2[in]++;
            if(hash2[in]==hash1[in]) count++;
            while(count==len)//更新并出窗口
            {
                if(right-left+1<minlen)
                {
                    minlen=right-left+1;
                    begin=left;
                }
                char out=s[left];
                if(hash2[out]==hash1[out]) count--;
                hash2[out]--;
                left++;   
            }
        }
        if(begin==-1) return "";
        return s.substr(begin,minlen);
    }
};

五.总结

        相对于暴力解法而言滑动窗口本质其实是减少不必要的枚举,那么当我们做题时一眼看不出可以使用滑动窗口或者知道要使用滑动窗口但不知道如何用的时候,我们就可以从暴力枚举的角度出发,从暴力中的寻找规律并优化。

1.滑动窗口算法的使用场景

1.1.连续子数组问题
        (1)固定窗口大小:例如,给定一个数组和窗口大小,求窗口内元素的和、最大值、最小值等。
        (2)可变窗口大小:例如,在一个数组中找到和为某一特定值的子数组,需要根据条件动态调整窗口的左右边界。
1.2.字符串子串问题
        例如,在一个字符串中查找包含特定字符集合的最短子串,或者判断一个字符串是否包含另一个字符串的排列等。

2.滑动窗口算法的基本步骤

2.1. 扩展窗口
        移动右指针来扩大窗口,直到窗口满足特定的条件或者达到数组/字符串的边界。在每次移动右指针时,更新窗口的状态变量。
2.2. 收缩窗口
        当窗口满足特定条件后,开始移动左指针来收缩窗口,同时继续更新窗口的状态变量。收缩窗口的过程是为了找到满足条件的最小窗口或者统计所有满足条件的窗口。
2.3. 更新结果
        根据窗口的状态和问题的要求,更新最终的结果,结果可能是窗口的大小、窗口内元素的某种统计值等。
 
  

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

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

相关文章

小米红米系列机型 机型代码查询总目录 adb指令查询步骤

小米机型型号与代码 小米系列机型 型号众多。有时候我们在刷机或者下载固件的时候对一些 同型号分版本的机型不太注意下错固件刷机会导致系统故障。手机设备代码虽然在一般情况下用处不大&#xff0c;不过真正到你需要它的时候&#xff0c;又苦于不知道它是什么&#xff0c;以…

Acrobat Pro DC 2023 for Mac/Win:全能型PDF编辑器深度解析

Adobe Acrobat Pro DC 2023作为一款跨平台的PDF编辑器&#xff0c;无论是对于Mac还是Windows用户&#xff0c;都提供了极为全面且强大的PDF处理功能。该软件凭借其卓越的性能和丰富的特性&#xff0c;成为了全球范围内用户处理PDF文档的首选工具。 一、强大的编辑功能 Acroba…

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题&#xff0c;本文将一起从代码层去分析为什么没有建立索引&#xff1f; 开源ERP项目地址&#xff1a;…

Windows系统引入全新 Android 体验?快来尝鲜!

听说微软 Windows 11 操作系统引入全新体验 &#xff1a;实时访问 Android 设备图片。 意思就是在Android 设备上捕获了新照片或屏幕截图时&#xff0c;Windows 上立刻收到通知&#xff0c;且可以不用插数据线就能访问。 用Windows连接手机的功能其实早在Windows10就已经有的了…

【进阶篇】应届毕业生必备:机器学习面试题指南【2】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

总线概述

CPU能通过地址总线给主存、硬盘、打印机通过地址总线发送地址&#xff0c;CPU可以通过数据总线和其他的部件进行信息传输&#xff0c;地址总线和数据总线可以并行传输很多位信息&#xff0c;为什么呢&#xff1f;因为每个总线可能由很多跟信号线组成的。CPU可以通过控制总线给其…

锐捷交换机常用命令

文章目录 1. 基本操作命令2. 接口配置3. VLAN配置4. 链路聚合5. 生成树协议6. 端口安全7. 常用查看命令8. 系统管理9. 配置端口镜像10. 配置生成树协议 1. 基本操作命令 进入特权模式&#xff1a;enable 进入全局配置模式&#xff1a;configure terminal 保存配置&#xff1a;…

在线plotly绘制动态旭日图,展示复杂数据层次结构

探索数据的层次之美&#xff1a;旭日图&#xff0c;以环环相扣的视觉效果&#xff0c;清晰展现数据的层级关系。搭配Plotly的动态可视化技术&#xff0c;不仅让数据层次一目了然&#xff0c;更通过交互式操作&#xff0c;让用户轻松探索每个层级的详细信息&#xff0c;享受数据…

国内web组态推荐

万维组态是一款功能强大的基于Web的可视化组态编辑器&#xff0c;采用标准HTML5技术&#xff0c;基于B/S架构进行开发&#xff0c;支持WEB端呈现&#xff1b; 支持在浏览器端完成便捷的人机交互&#xff0c;简单的拖拽即可完成可视化页面的设计;可快速构建和部署可扩展的SCADA…

关于百度翻译以及这三款好用的翻译推荐!!

今天咱来聊聊在线翻译工具&#xff0c;尤其是百度翻译&#xff0c;以及我超爱的其他几款翻译工具。如果你跟我一样&#xff0c;经常要处理多语言文件&#xff0c;或者想快速了解外国文化&#xff0c;那么这些工具绝对是你的好帮手&#xff1a; 关于百度翻译 先说说我日常用的…

低温烧结银AS9378火爆的六大原因

低温烧结银AS9378火爆的六大原因 低温烧结银AS9378近年来在电子材料领域迅速崛起&#xff0c;其火爆程度令人瞩目。这款采用纳米技术和低温烧结工艺的高性能材料&#xff0c;凭借其独特的优势在众多应用中脱颖而出。以下&#xff0c;我们将深入探讨低温烧结银AS9378火爆的六大原…

纷享销客生态伙伴大会北京站成功举办,共谋数智新未来

9月5日&#xff0c;主题为“智享未来 领创CRM新纪元”的纷享销客生态伙伴大会北京站圆满落幕&#xff0c;此次盛会吸引了超过600位来自不同行业的精英代表、企业领袖、技术专家等汇聚一堂&#xff0c;共同探讨CRM领域的最新趋势、创新实践与未来机遇。 01、智享未来&#xff0…

idea修改内存设置后,启动没反应 Error opening zip file or JAR manifest missing :

Error opening zip file or JAR manifest missing :一个路径 解决办法 删除环境变量中的路径 重装idea

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始&#xff0c;按照书籍的划分&#xff0c;第10章开始就进入保护模式&#xff08;Protected Mode&#xff09;部分了&#xff0c;感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断&#xff08;Interrupt&#xff09;的设计&#…

idea开发Java程序的步骤及设置

project中可以创建多个module&#xff0c;module中可以创建多个package。package中可以创建多个class。 idea中的Java程序是自动编译和执行的&#xff0c;编译后的class文件在工程路径下的一个out文件夹里。 IDEA中设置主题、字体 IDEA常用快捷键

Ubuntu20如何设置网络

如图设置静态地址 第1步&#xff1a; 查看当前主机的网卡名&#xff0c;当前ip, 子网掩码&#xff0c;网关地址 ifconfig route -n 如果ifconfig命令无法使用, 请运行以下命令安装net-tools sudo apt update -y sudo apt install net-tools -y 如上图所示&#xff1a;网卡名为 …

Cesium 展示——实现雾的天气效果模拟

文章目录 需求分析1. 添加2. 移除需求 Cesium 完成雾的天气效果模拟 分析 1. 添加 源码case

C语言-qosrt函数—秩序大师

1、qsort()的作用 在我们的日常生活中&#xff0c;排序无处不在。想象一下&#xff0c;当你整理书架时&#xff0c;会按照书籍的类别、作者或者大小进行排列&#xff0c;让你的阅读空间更加整洁有序。又比如&#xff0c;在超市的货架上&#xff0c;商品通常也是按照一定的规则进…

启动与登录Mysql

1.启动与停止MYSQL服务 启动MySQL 服务的命令 以管理员身份打开Windows 的命令行窗口&#xff0c;在命令提示符后输入以下命令启动MySQL 服务&#xff1a; net start[ 服务名称] 也可以直接输入以下命令&#xff1a; net start 按【Enter】键执行该命令&#xff0c;默认启…

测试网站dddd

Selenium PostmanpythonPytest