算法:滑动窗口解决连续区间子数组问题

2023-11-15

本篇积累的是滑动窗口的问题,滑动窗口在算法实现中有重要作用,可以解决很多问题

实现原理

当遇到需要在题目中寻找一个符合条件的子数组时,或在一段区间内寻找一段连续的区间时,就可以用到这种算法,这个算法的原理就是用左右指针形成一个区间,这个区间用以寻找满足条件的区间

实现思路

具体的实现思路要依托于单调性从而进行同向双指针的优化

这里的单调性并非指的是数据顺序的递增或递减,而是说随着窗口的变大变小或滑动,窗口内数据的整体变化趋势,因此对于一些全为正数的数据量来说,滑动窗口是比较契合解决问题的

那么具体的使用就是定义两个指针,leftright,这两个指针用来作为窗口的左右窗框,这段区间中间的部分就是窗口

既然叫做滑动窗口,那么必然这两个指针是要动起来的,right就是所谓的进窗口,再进行判断是否需要出窗口,再更新结果即可


典型例题

长度最小的子数组

在这里插入图片描述

从此题中,其实可以看出滑动窗口是有其大体思路的,简单总结就是进窗口,判断,出窗口,代码形式多样,但核心思路不变,关键在于寻找while循环的条件,也就是出窗口部分的条件是什么

class Solution 
{
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int left=0,right=0,sum=0,len=INT_MAX;
        for(left=0,right=0;right<nums.size();right++)
        {
            // 进窗口
            sum+=nums[right];

            // 判断
            while(sum>=target)
            {
                // 出窗口
                len=min(len,right-left+1);
                sum-=nums[left];
                left++;
            }

        }
        return len==INT_MAX? 0:len;
    }
};

无重复字符的最小字串

在这里插入图片描述

此题的关键思路是找不重复的字串,如果重复就要寻找下一个,那么核心思路不变,依旧是进窗口,判断,出窗口,问题核心关键在于while循环,这里涉及到如果有重复元素在字串中就停止进窗口,因此可以借助一个哈希表来检测是否有重复元素,因此在这里创建一个数组哈希表即可

当检测到元素含有重复元素时,就进行出窗口,出窗口一直出到整个窗口中不含有该重复元素,使得可以继续进窗口找不重复序列

class Solution 
{
public:
    int lengthOfLongestSubstring(string s) 
    {
        int left=0,right=0,hash[128]={0},ret=0;
        for(left=0,right=0;right<s.size();right++)
        {
            // 进窗口
            hash[s[right]]++;
            
            // 判断
            while(hash[s[right]]>1)
            {
                // 出窗口
                hash[s[left++]]--;
            }
            ret=max(ret,right-left+1);
        }
        return ret;
    }
};

最大连续1的个数III

在这里插入图片描述

对于此题来说,如果直观去考虑,要按照题意反转数字再进行统计会相当麻烦,因此这里换一种思路进行问题解决

比如,这里可以把题意转换为,使得区间内的0的个数小于K

基于这样的考虑,就可以使用滑动窗口了,整体来看和前面的思维一样,只是需要有一个思维的转换,基于这样的情况下,代码实现并不困难

class Solution 
{
public:
    int longestOnes(vector<int>& nums, int k) 
    {
        int left=0,right=0,len=0,ret=0;
        for(left=0,right=0;right<nums.size();right++)
        {
            // 进窗口
            if(nums[right]==0)
            {
                ret++;
            }

            // 判断
            if(ret>k)
            {
                // 出窗口
                while(nums[left++]!=0);
                ret--;
            }

            len=max(len,right-left+1);
        }
        return len;
    }
};

由此可见,滑动窗口就是三部曲 进窗口,判断,出窗口
掌握整个原理即可应对滑动窗口的问题

将x减到0的最小操作

在这里插入图片描述

本题用到了一个正难则反的思想,把问题转换为求中间部分的最大值即可,这里要注意对于如果中间没有找到内容要进行记录的问题,并且要一直找下去,要注意更新数据的位置

class Solution 
{
public:
    int minOperations(vector<int>& nums, int x) 
    {
        int sum=0;
        for(int i=0;i<nums.size();i++)
        {
            sum+=nums[i];
        }
        int tmp=sum-x;

        if(tmp<0)
        {
            return -1;
        }

        int left=0,right=0,len=-1,ret=0;
        for(int left=0,right=0; right<nums.size();right++)
        {
            // 进窗口
            ret+=nums[right];

            // 判断
            while(ret>tmp)
            {
                // 出窗口
                ret-=nums[left];
                left++;
            }

            if(ret==tmp)
            {
                len=max(len,right-left+1);
            }
        }
        return len==-1? len:(nums.size()-len);
    }
};

水果成篮

在这里插入图片描述

class Solution 
{
public:
    int totalFruit(vector<int>& fruits)
    {
        int hash[100001] = { 0 }, kind = 0, len = 0;
        for (int left = 0, right = 0; right < fruits.size(); right++)
        {
            // 进窗口
            if (hash[fruits[right]] == 0)
            {
                kind++;
            }
            hash[fruits[right]]++;

            // 判断
            while (kind > 2)
            {
                // 出窗口
                hash[fruits[left]]--;
                if (hash[fruits[left]] == 0)
                {
                    kind--;
                }
                left++;
            }

            len = max(len, right - left + 1);
        }
        return len;
    }
};

找到字符串中所有字母异位词(哈希表比较优化)

在这里插入图片描述

本题也是滑动窗口的经典题目,和前面不同的是窗口长度是固定的,但整体上遵循进窗口,判断,出窗口的规则就可以解决,但这当中有些许步骤可以优化

先看正常方法如何进行代码编写

class Solution 
{
public:
    bool hashcmp(int a[], int b[], int sz)
    {
        for (int i = 0; i < sz; i++)
        {
            if (a[i] != b[i])
                return false;
        }
        return true;
    }

    vector<int> findAnagrams(string s, string p)
    {
        vector<int> v;
        int hash1[26] = { 0 };
        int hash2[26] = { 0 };
        // p内数据扔到hash1中
        for (auto ch : p)
        {
            hash1[ch - 'a']++;
        }

        for(int left=0,right=0;right<s.size();right++)
        {
            // 进窗口
            char in=s[right];
            hash2[in-'a']++;

            // 判断
            if(right-left+1==p.size())
            {
                if(hashcmp(hash1,hash2,26))
                {
                    v.push_back(left);
                }
                // 出窗口
                char out=s[left];
                hash2[out-'a']--;
                left++;
            }
        }
        return v;
    }
};

这里用数组模拟了两个哈希表,一个哈希表用来存储的是要找的子字符串的数据,另外一个哈希表内存的是滑动窗口内字符串的数据

这里有一个哈希表比较的问题,决定最终能否将left放到vector中的条件就是看这两个哈希表中的元素是否相同,如果相同就可以放到vector

但比较是个问题,对于这个题来说哈希表中我们只存放了26个字符,比较也只需要比较26次就可以得出结论,但如果这里存放的内容不仅仅是小写字母,还有其他字母?那此时这里再使用每一个元素进行遍历就显得很差,因此这里可以采取一些措施进行相应的优化

对哈希表内元素比较的优化

这个优化方法是采用一个count变量用以表示哈希表中有效字符的个数,假设这里采用的子字符串是abc

那么当入窗口是a的时候,此时哈希表中a的元素对应的数据是0,就可以入数据,此时这个a隶属于有效数据,可以入窗口,但如果要继续入数据a,此时子字符串对应的哈希表中字符a的数据量是1,而滑动窗口中对应的哈希表中字符a对应的数据量已经满足要求了,如果再入该数据则说明这个a是无效的数据,此时count就不进行增加

那么这个有什么用?count进行有效数据的维护和两个哈希表的比较有什么关系?

其实结论在于,在最后判断的时候,如果有效字符的数量和滑动窗口的长度相同,就恰恰说明了滑动窗口对应的哈希表中的数据和子字符串的哈希表中对应的数据是相同的,因此这两个哈希表就是相同的,也就达到了比较哈希表的目的

class Solution 
{
public:

    vector<int> findAnagrams(string s, string p)
    {
        int count=0;
        vector<int> v;
        int hash1[26] = { 0 };
        int hash2[26] = { 0 };
        // p内数据扔到hash1中
        for (auto ch : p)
        {
            hash1[ch - 'a']++;
        }

        for(int left=0,right=0;right<s.size();right++)
        {
            // 进窗口
            char in=s[right];
            hash2[in-'a']++;
            if(hash2[in-'a']<=hash1[in-'a'])
            {
                count++;
            }

            // 判断
            if(right-left+1>p.size())
            {
                // 出窗口
                char out=s[left];
                if(hash2[out-'a']<=hash1[out-'a'])
                {
                    count--;
                }
                hash2[out-'a']--;
                left++;
            }

            if(count==p.size())
            {
                v.push_back(left);
            }
        }
        return v;
    }
};

总结

滑动窗口其实本质可以作为是一种同向的双指针,主要需要遵循的步骤就是进窗口,判读,出窗口,只要找到合适的循环条件,解决问题并不困难

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

算法:滑动窗口解决连续区间子数组问题 的相关文章

  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • 将类对象放置在向量中?

    我注意到我可以将一个类放置在一个向量中 这是我的程序 我收到以下错误 out blackjack exe blackjack obj blackjack obj error LNK2019 unresolved external symbo
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 传递 constexpr 对象

    我决定给予新的C 14的定义constexpr旋转并充分利用它 我决定编写一个小的编译时字符串解析器 然而 我正在努力保持我的对象constexpr将其传递给函数时 考虑以下代码 include
  • 如何将 .txt 文件中的数据转换为 xml? C#

    我在一个文本文件中有数千行数据 我想通过将其转换为更容易搜索的内容来轻松搜索 我希望 XML 或其他类型的大型数据结构 尽管我不确定它是否是最好的对于我的想法 每行的数据如下所示 第 31 册 托马斯 乔治 32 34 154 每本书都不是
  • 处理右值时的 insert 与 emplace

    std string myString std unordered set
  • 强制初始化模板类的静态数据成员

    关于模板类的静态数据成员未初始化存在一些问题 不幸的是 这些都没有能够帮助我解决我的具体问题的答案 我有一个模板类 它有一个静态数据成员 必须为特定类型显式实例化 即必须专门化 如果不是这种情况 使用不同的模板函数应该会导致链接器错误 这是
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 在 .NET MAUI 中实现 TouchTracking

    我一直致力于将我们的应用程序从 Xamarin Forms 迁移到 NET MAUI 我们的应用程序几乎没有绘图功能 用户可以用手指进行绘图 我们用了TouchTrackingXamarin Forms 中的 nuget 包 但与 NET
  • 模板外部链接?谁能解释一下吗?

    模板名称具有链接 3 5 非成员函数模板可以有内部链接 任何其他模板名称应具有外部链接 从具有内部链接的模板生成的实体与在其他翻译单元中生成的所有实体不同 我知道使用关键字的外部链接 extern C EX extern C templat
  • 在 C# 中为父窗体中的子窗体控件添加事件处理程序

    我有两种形式 一种是带有按钮和文本框的父表单 单击该按钮时 将打开一个对话框 该子窗体又包含一个文本框和一个按钮 现在我想要的是 每当子表单文本框中的文本更改时 父表单文本框中的文本会自动更改 为了获得这个 我所做的是 Form3 f3 n
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • C++ - 多维数组

    处理多维数组时 是否可以为数组分配两种不同的变量类型 例如你有数组int example i j 有可能吗i and j是两种完全不同的变量类型 例如 int 和 string 听起来您正在寻找 std vector
  • Oauth2中如何同时撤销RefreshToken和使AccessToken失效

    我正在使用 Owin Oauth2 授权和资源服务器相同 开发单页面应用程序 AngularJS Net MVC Json Rest API 的身份验证流程 我选择了 Bearer Token 路由而不是传统的 cookie session
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • C++:二叉树所有节点值的总和

    我正在准备面试 我被一个二叉树问题困住了 我们如何计算二叉树所有节点中存在的值的总和 优雅的递归解决方案 伪代码 def sum node if node NULL return 0 return node gt value sum nod
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person
  • MySqlConnectionStringBuilder - 使用证书连接

    我正在尝试连接到 Google Cloud Sql 这是一个 MySql 解决方案 我能够使用 MySql Workbench 进行连接 我如何使用 C 连接MySqlConnectionStringBuilder 我找不到提供这三个证书的

随机推荐

  • 列可以设置 :formatter,对列的值进行处理

    需要对数字进行处理
  • 美图2022年财报:AIGC引领创新,多重驱动共振向上

    2022年是美图发展的关键之年 在数字化趋势加速的背景下 美图通过持续优化用户体验和不断拓展业务领域边界 进一步巩固了其行业竞争优势 近日 美图公司发布2022财年年度业绩 在收入 用户 创新等方面均取得了令人瞩目的成绩 展现了强劲的发展势
  • VMware导入vmdk文件(亲测有效)

    场景 从别的地方拷贝了一个系统镜像 后缀是vmdk格式 现在演示如何导入到本地 操作步骤 打开vmware 点击文件 新建虚拟机 2 选择自定义 高级 下一步 3 硬件兼容性 默认选择最新的行 因为和本地安装的vmware版本有关 这里演示
  • Fiddler笔记(一)

    个人学习笔记 整理不易 有帮助点个赞 笔记目录 学习笔记目录 pytest和unittest airtest weixin 42717928的博客 CSDN博客 目录 一 简单了解 二 下载安装 三 工具使用 四 HTTP协议报文结构 1
  • 【操作系统】Linux常用基础和高级命令

    目录 一 Linux内核 二 Linux发行版 操作系统 三 Linux终端 三 Linux终端命令 1 命令格式 2 常用基础命令 1 查看目录命令 2 切换目录命令 3 创建文件和目录命令 4 删除文件和目录命令 5 复制文件和目录命令
  • 使用LeNet实现图像分类任务

    本篇的主要内容是解析一下使用MindSpore深度学习框架训练LeNet网络对Mnist数据集进行分类 首先我给大家展示出本篇内容的一个示意图 帮助大家更直观的看到训练过程的一个重要步骤 如图所示 其中1 2 3 表示训练过程中的次序 下面
  • RSA密码原理详解及算法实现(六步即可掌握)

    一 RSA算法概述 rsa算法是一种非对称加密算法 其安全性是建立在大素数难以分解的基础上的 即将两个大素数相乘十分容易 但想对其乘积进行分解却很困难 所以可以将其乘积公开作为加密密钥 二 RSA算法设计理念 根据数论 寻求两个大素数比较简
  • mysql默认值语句

    添加新字段 并设置默认值 alter table test tb add column col3 varchar 20 not null DEFAULT abc 修改原有默认值 alter table test tb alter colum
  • springboot整合logback

    1 在springboot项目resource目录下 创建一个 logback spring xml 文件 2 在logback spring xml文件中添加内容
  • vscode代码统计

    1 安装插件 在vscode界面左侧 点击图中所示的菜单项 搜索Vscode counter 2 使用插件统计代码 点击顶部 View 菜单 gt 在下拉选项中选择第一项 Command Palette gt 工作区选择VscodeCoun
  • 循环机换变速箱油教程_循环机更换自动变速箱油,需要更换的车友可以先了解一下...

    前言 了解汽车知识 让每一位车主维修保养不花冤枉钱 胖哥闲置快半年的自动变速箱循环机 今天终于再次开张了 说起这玩意一年也用不了几次 没有还真不行 自动变速箱油一般6万公里更换 具体大家可根据自己的 车辆保养手册规定 自动变速箱油更换有三种
  • ffmpeg视频裁剪

    需要注意 ffmpeg 命令 s 指定了宽高后 如果为奇数宽高 101 101 则裁剪后的视频无法正常播放 不加 s则ffmpeg自动 1处理 private void cutVideo throws Exception try Strin
  • 数组及常用方法

    思维导图 数组的基本概念 什么是数组 数组是存储一个或多个数据的容积 它是一组内存空间 通常用来批量处理数据 这组内存空间的名字叫做数组2 数组的特点 对齐自身储存的数据并没有什么要求 无论是数量还是类型 数组中的每一项可以是任意一种数据类
  • Eviews导入外部Excel数据并回归分析

    本文是计量学习中学习笔记 下面直接放截图 导入数据在这一步之前 需要注意Excel中的数据文件不能有中文字符 否则会报错 回归时需要先选中被解释变量 同时按住Ctrl建依次再选中解释变量 回归结果中可以看出 3 6的参数是不过检的 这说明原
  • cadence学习笔记(5)-从其他PCB(AD、PADS)导出Allegro使用的封装库

    一 AD转Allegro封装库 1 AD转ASCLL文件 2 一定要选择ASCLL文件 3 打开Allegro软件导入刚刚生成的PCB文件 4 转化完成的PCB AD原PCB 5 导出AllegroPCB封装库 6 生成的封装库文件 二 P
  • uni-app全局变量的存储和页面数据之间的传递

    https ask dcloud net cn article 35021 目录 1 变量存储 1 1使用公用模块存储 就是一个公共的页面 1 2 挂载到 Vue prototype存储 1 3使用globalData存储 1 4 使用vu
  • 阿里巴巴2014笔试总结

    昨天去笔试的 对我一个非计算机系的真的是略难 今天还能回忆起几道题目 就贴上来当个总结吧 单选第三题 比较两段程序哪个的效率更高 t1 for i 0 i lt 1000000 i for j 0 j lt 100 j expression
  • windows下的C++ socket服务器(2)

    博客园 闪存 首页 新随笔 联系 管理 订阅 随笔 16 文章 0 评论 33 windows下的C socket服务器二 int make server socket int port 1 void handleAccept int so
  • Windows 使用第三方工具curl 模拟GET 请求

    Windows环境之Curl下载地址 https curl se windows Curl 基本用法 1 访问百度网页 并将网页源码保存到本地 curl o news txt www baidu com 2 访问百度网页 并显示请求头部信息
  • 算法:滑动窗口解决连续区间子数组问题

    文章目录 实现原理 实现思路 典型例题 长度最小的子数组 无重复字符的最小字串 最大连续1的个数III 将x减到0的最小操作 水果成篮 找到字符串中所有字母异位词 哈希表比较优化 对哈希表内元素比较的优化 总结 本篇积累的是滑动窗口的问题