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

文章目录

  • 实现原理
  • 实现思路
  • 典型例题
    • 长度最小的子数组
    • 无重复字符的最小字串
    • 最大连续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;
    }
};

总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PP-TS基于启发式搜索和集成方法的时序预测模型,使预测更加准确

时间序列数据在各行业和领域中无处不在&#xff0c;如物联网传感器的测量结果、每小时的销售额业绩、金融领域的股票价格等等&#xff0c;都是时间序列数据的例子。时间序列预测就是运用历史的多维数据进行统计分析&#xff0c;推测出事物未来的发展趋势。 为加快企业智能化转型…

JRebel插件扩展-mac版

前言 上一篇分享了mac开发环境的搭建&#xff0c;但是欠了博友几个优化的债&#xff0c;今天先还一个&#xff0c;那就是idea里jRebel插件的扩展。 一、场景回眸 这个如果在win环境那扩展是分分钟&#xff0c;一个exe文件点点就行。现在在mac环境就没有这样的dmg可以执行的&…

十七、地物识别

描述了使用2D卷积神经网络图像识别的全过程。下载和安装标注工具,对图像进行标注,生成标注后的图像。然后对数据进行增强,划分训练集和测试集。最后通过神经网络建立分类模型,对现有图片进行分类应用。 1、Labelme工具 Labelme工具是语义分割标注工具,在地物类型或建…

汽车领域专业术语

1. DMS/OMS/RMS/IMS DMS&#xff1a;即Driver Monitoring System&#xff0c;监测对象为Driver&#xff08;驾驶员&#xff09;。DMS三大核心&#xff1a; OMS&#xff1a;即Occupancy Monitoring System&#xff0c;监测对象为乘客。 RMS&#xff1a;后排盲区检测系统 IMS&…

代理模式概述

1.代理模式概述 学习内容 1&#xff09;概述 为什么要有 “代理” &#xff1f; 生活中就有很多例子&#xff0c;比如委托业务&#xff0c;黄牛&#xff08;票贩子&#xff09;等等代理就是被代理者没有能力或者不愿意去完成某件事情&#xff0c;需要找个人代替自己去完成这…

micropython SSD1306/SSD1315驱动

目录 简介 代码 功能 显示ASCII字符 ​编辑 画任意直线 画横线 画竖线 画矩形 画椭圆 画立方体 画点阵图 翻转 反相 滚动 横向滚动 纵向滚动 奇葩滚动 简介 我重新写了一个驱动&#xff0c;增加了一些功能&#xff0c;由于我的硬件是128*64oled单色I2C&#xff0c;我只…

Android Shape 的使用

目录 什么是Shape? shape属性 子标签属性 corners &#xff08;圆角&#xff09; solid &#xff08;填充色&#xff09; gradient &#xff08;渐变&#xff09; stroke &#xff08;描边&#xff09; padding &#xff08;内边距&#xff09; size &#xff08;大小…

视频高效剪辑,轻松平均分割视频,生成高质量M3U8

您是否在处理视频剪辑时常常面临繁琐的切分工作&#xff1f;是否希望能够快速而精准地平均分割视频&#xff0c;并生成适用于在线播放的高质量m3u8文件&#xff1f;现在&#xff0c;我们的智能视频剪辑大师为您提供了一种简便而高效的解决方案&#xff01;无需复杂操作&#xf…

【MySQL系列】--初识数据库

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

软件报错msvcr90.dll丢失的解决方法,亲测可以修复

我曾经遇到过一个令人头疼的问题&#xff1a;msvcr90.dll丢失。这个问题导致了我的程序无法正常运行&#xff0c;让我感到非常苦恼。然而&#xff0c;在经过一番努力后&#xff0c;我终于成功地修复了这个问题&#xff0c;这让我感到非常欣慰和满足。 msvcr90.dll丢失的原因可能…

大模型基础03:Embedding 实战本地知识问答

大模型基础:Embedding 实战本地知识问答 Embedding 概述 知识在计算机内的表示是人工智能的核心问题。从数据库、互联网到大模型时代,知识的储存方式也发生了变化。在数据库中,知识以结构化的数据形式储存在数据库中,需要机器语言(如SQL)才能调用这些信息。互联网时代,…

117页数字化转型与产业互联网发展趋势及机会分析报告PPT

导读&#xff1a;原文《》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 喜欢文章&#xff0c;您可以点赞评论转发本文&#xff0c;了解更多内容请私信&#xff1a;方…

__format__和__del__

目录 一、__format__ 二、__del__ python从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129328397?spm1001.2014.3001.5502 一、__format__ 自定制格式化字符串 date_dic {ymd: {0.year}:{0.month}:{0.day},dmy: {0.day}/{0.month}/…

力扣 198. 打家劫舍

题目来源&#xff1a;https://leetcode.cn/problems/house-robber/description/ C题解&#xff1a;因为是间接偷窃&#xff0c;所以偷nums[i]家前&#xff0c;一定偷过第i-2或者i-3家&#xff0c;因为i-1不能偷。 例如12345共5家&#xff0c;先偷第1家&#xff0c;那么2不能偷…

Oracle切割字符串的方法,SQL语句完成。

Oracle用正则的方式循环切割字符串 需求&#xff1a;有一个这样子的 Str “‘CNJ-520-180500000001|CNJ-520-181200000001|CNJ-520-190300000001|CNJ-520-190100000001|CNJ-520-181200000002’” &#xff0c;然后我需要拿到每一个单号&#xff0c;每一个单号都要走一遍固定的…

神经网络基础-神经网络补充概念-03-逻辑回归损失函数

概念 逻辑回归使用的损失函数通常是"对数损失"&#xff08;也称为"交叉熵损失"&#xff09;或"逻辑损失"。这些损失函数在训练过程中用于衡量模型预测与实际标签之间的差异&#xff0c;从而帮助模型逐步调整权重参数&#xff0c;以更好地拟合数…

vue3小知识点汇总——基础积累

下面的小知识点比较零散&#xff0c;但是脑子不太好使&#xff0c;只能先记录一下啦&#xff0c;后面知识丰富起来后&#xff0c;慢慢就懂了。 1.最新版node.js已经不兼容vue2的项目了&#xff0c;学习vue3势在必行 node.js的安装及vue的搭建详细步骤&#xff1a;http://t.cs…

知识继承概述

文章目录 知识继承第一章 知识继承概述1.背景介绍第一页 背景第二页 大模型训练成本示例第三页 知识继承的动机 2.知识继承的主要方法 第二章 基于知识蒸馏的知识继承预页 方法概览 1.知识蒸馏概述第一页 知识蒸馏概述第二页 知识蒸馏第三页 什么是知识第四页 知识蒸馏的核心目…

冠达管理:哪里查中报预增?

中报季行将到来&#xff0c;投资者开端重视公司的成绩体现。中报预增是投资者最关心的论题之一&#xff0c;因为这意味着公司未来成绩的增加潜力。但是&#xff0c;怎么查找中报预增的信息呢&#xff1f;本文将从多个视点分析这个问题。 1.证券交易所网站 证券交易所网站是投资…

如何用输入函数为数组赋值

在编写程序时我们经常使用数组&#xff0c;而数组的大小可能是很大的但是我们并不需要为每个元素都自己赋值&#xff0c;我们可能会自定义输入数组元素个数&#xff0c;我们应该如何实现通过输入函数为数组赋值呢&#xff1f; 目录 第一种&#xff1a; 第二种&#xff1a; 第一…