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

news2024/9/24 9:25:19

文章目录

  • 实现原理
  • 实现思路
  • 典型例题
    • 长度最小的子数组
    • 无重复字符的最小字串
    • 最大连续1的个数III
    • 将x减到0的最小操作
    • 水果成篮
    • 找到字符串中所有字母异位词(哈希表比较优化)
      • 对哈希表内元素比较的优化
  • 总结

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

实现原理

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

实现思路

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

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

那么具体的使用就是定义两个指针,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;
    }
};

总结

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

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

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

相关文章

Python可视化在量化交易中的应用(16)_Seaborn热力图

Seaborn中热力图的绘制方法 seaborn中绘制热力图使用的是sns.heatmap()函数&#xff1a; sns.heatmap(data,vmin,vmax,cmap,center,robust,annot,fmt‘.2g’,annot_kws,linewidths0,linecolor‘white’,cbar,cbar_kws,cbar_ax,square,xticklabels‘auto’,yticklabels‘auto’…

systemd:初学者如何理解其中的争议

导读对于什么是 systemd&#xff0c;以及为什么它经常成为 Linux 世界争议的焦点&#xff0c;你可能仍然感到困惑。我将尝试用简单的语言来回答。 在 Linux 世界中&#xff0c;很少有争议能像传统的 System V 初始化 系统&#xff08;通常称为 SysVinit&#xff09;和较新的 s…

QT设置widget背景图片

首先说方法&#xff0c;在给widget或者frame或者其他任何类型的控件添加背景图时&#xff0c;在样式表中加入如下代码&#xff0c;指定某个控件&#xff0c;设置其背景。 类名 # 控件名 { 填充方式&#xff1a;图片路径 } 例如&#xff1a; QWidget#Widget {border-image: url…

1. 微信小程序开发环境搭建

下载 微信的小程序开发需要使用到微信开发者工具&#xff0c;通过https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html可以下载 下载完成后 安装

Linux 系统编程拾遗

Linux 系统编程拾遗 进程的创建 进程的创建 fork()、exit()、wait()以及execve()的简介 创建新进程&#xff1a;fork()

人工智能原理(6)

目录 一、机器学习概述 1、学习和机器学习 2、学习系统 3、机器学习发展简史 4、机器学习分类 二、归纳学习 1、归纳学习的基本概念 2、变型空间学习 3、归纳偏置 三、决策树 1、决策树组成 2、决策树的构造算法CLS 3、ID3 4、决策树的偏置 四、基于实例的学习…

嵌入式系统总线-片内总线

1.总线概述 总线是CPU与存储器和设备通信的机制&#xff0c;是计算机各部件之间传送数据、地址和控制信息的公共通道。 2.总线参数 总线宽度&#xff1a;又称总线位宽&#xff0c;指的是总线能同时传送数据的位数。如16位总线就是具有16位数据传送能力。 总线频率&#xff…

apex安装出错:TypeError unsupported operand type(s) for +: “NoneType“ and “str“

Windows 10 环境下安装apex报错&#xff1a;TypeError unsupported operand type(s) for : “NoneType“ and “str“ 1、首先apex不能直接pip install apex安装。 2、具体安装步骤&#xff1a;【python】【深度学习】apex的安装_apex python_愿东大没有食堂的博客-CSDN博客 …

深入竞品:解读竞品分析的艺术与策略

引言&#xff1a;为何竞品分析至关重要&#xff1f; 在当今的产品环境中&#xff0c;市场变得越来越拥挤。每个角落都有新的创业公司试图创造下一个行业的颠覆者&#xff0c;同时也有成熟的巨头在不断地迭代和优化他们的产品。在这样的环境中&#xff0c;不了解您的竞争对手是…

『C语言初阶』第八章 -结构体

前言 今天小羊又来给铁汁们分享关于C语言的结构体&#xff0c;在C语言中&#xff0c;结构体类型属于一种构造类型&#xff08;其他的构造类型还有&#xff1a;数组类型&#xff0c;联合类型&#xff09;&#xff0c;今天我们主要简单了解一下结构体。 一、结构体是什么&#x…

Linux Mint 21.3 计划于 2023 年圣诞节发布

Linux Mint 项目近日公布了基于 Ubuntu 的 Linux Mint 发行版下一个重要版本的一些初步细节&#xff0c;以及备受期待的基于 Debian 的 LMDE 6&#xff08;Linux Mint Debian Edition&#xff09;版本。 近日&#xff0c;Linux Mint 项目负责人克莱门特-勒菲弗&#xff08;Clem…

ECA模块详解

注意&#xff1a;本文代码为自己理解之后实现&#xff0c;与原论文代码原理相同但并不完全一样&#xff0c;主要是输入张量的形状不同&#xff0c;若更想了解原文代码&#xff0c;可以访问&#xff1a;https://blog.csdn.net/weixin_45084253/article/details/124282580 &#…

使用RDP可视化远程桌面连接Linux系统

使用RDP可视化远程桌面连接Linux系统 远程桌面连接Linux安装安装包准备服务器安装xrdp远程连接 远程桌面连接Linux 通常使用SSH来连接服务器&#xff0c;进行命令行操作&#xff0c;但是这次需要远程调试生产环境的内网服务器&#xff0c;进行浏览器访问内网网站&#xff0c;至…

SQL助你面大厂(行列转换)

在面试中,不仅有算法题,还有这个老大难的SQL编写 SQL在面试中也是会经常会被问到&#xff0c;不仅仅是为了面试&#xff0c;在做项目的时候&#xff0c;往往用的最多的就是CRUD,这也提高不了我们的编写SQL的能力&#xff0c;所以最近我准备总结几个面试模板&#xff0c;以及一些…

webshell实践,在nginx上实现负载均衡

1、配置多台虚拟机&#xff0c;用作服务器 在不同的虚拟机上安装httpd服务 我采用了三台虚拟机进行服务器设置&#xff1a;192.168.240.11、192.168.240.12、192.168.240.13 [rootnode0-8 /]# yum install httpd -y #使用yum安装httpd服务#开启httpd服务 [rootnode0-8 /]# …

开发一个文生图的功能

文章目录 效果开发环境原理核心代码代码仓库问题效果 开发环境 Python 3.10PyCharm原理 借助开源项目stable-diffusion,通过该项目封装python库diffusers,可以轻易的实现文生图的功能。 关于更多diffusers的功能请访问:https://huggingface.co/docs/diffusers/index 核心代…

Linux命令200例:nc非常有用的网络工具(常用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

LeetCode128.最长连续序列

我这个方法有点投机取巧了&#xff0c;题目说时间复杂度最多O(n),而我调用了Arrays.sort(&#xff09;方法&#xff0c;他的时间复杂度是n*log(n)&#xff0c;但是AC了&#xff0c;这样的话这道题还是非常简单的&#xff0c;创建一个Hashmap&#xff0c;以nums数组的元素作为ke…

回归预测 | MATLAB实现GWO-SVM灰狼优化算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现GWO-SVM灰狼优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现GWO-SVM灰狼优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基…