草庐IT

【LeetCode算法成长之路】滑动窗口算法总结与经典题目分析

小新要变强 2023-06-15 原文

前言

本文小新为大家带来 滑动窗口算法 相关知识,经过对滑动窗口算法类题目的总结,为大家分享滑动窗口算法概述(包括:滑动窗口算法思想滑动窗口算法使用场景滑动窗口算法使用思路),滑动窗口算法代码模板,以及两个经典例题(长度最小的子数组最小覆盖子串),帮助大家更好的理解与掌握滑动窗口算法~

不积跬步,无以至千里;不积小流,无以成江海。每天进步一点点,在成为强者的路上,小新与大家共同成长!

📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)


目录

文章标题

一、滑动窗口算法概述

1️⃣滑动窗口算法思想

滑动窗口算法是在给定特定窗口大小(当然也可以是动态可变窗口)的数组或者字符串上进行操作的算法,该算法主要的用途就是在于将嵌套循环时间复杂度的效率优化成为线性时间复杂度。简而言之,滑动窗口算法在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度。

从字面意思上理解的话:

滑动: 说明这个窗口是移动的,也就是移动是按照一定方向来的。

窗口: 窗口大小并不是固定的,可以不断扩容直到满足一定的条件;也可以不断缩小,直到找到一个满足条件的最小窗口;当然也可以是固定大小。

一般来讲,滑动窗口算法需要借助两个指针left与right来完成。

2️⃣滑动窗口算法使用场景

一般可以使用滑动窗口算法的题目中会包含以下关键词:

  • 满足XXX条件(计算结果,出现次数,同时包含)
  • 最长/最短
  • 子串/子数组/子序列

例如: 长度最小的子数组

3️⃣滑动窗口算法使用思路

滑动窗口算法使用思路(寻找最长):

  • 核心: 左右双指针(L, R)在起始点,通过循环R向右逐位移动,直到R移到最后位置;
  • 每次滑动过程中:如果窗内元素满足条件,R向右移动扩大窗口,并更新最优结果;如果窗内元素不满足条件,L向右移动缩小窗口。

滑动窗口算法使用思路(寻找最短):

  • 核心: 左右双指针(L, R)在起始点,通过循环R向右逐位移动,直到R移到最后位置;
  • 每次滑动过程中:如果窗内元素不满足条件,R向右移动扩大窗口,并更新最优结果;如果窗内元素满足条件,L向右移动缩小窗口。

二、滑动窗口算法代码模板

寻找最长问题的模板:

// left,right指针分别指向窗口的左边与后边位置
// result用来保存计算的结果,该结果需要满足一定的条件
// baseResult用来保存需要求得的结果:最长的长度
初始化left,right, result, bestResult;

while(右指针没有到结尾) {
    窗口扩大,加入right对应元素,更新当前result;
    while(result不满足要求){
        窗口缩小,移除left对应元素,left右移;
    }
    更新最优结果到bestResult;
    right++;
}

return bestResult;

寻找最短问题的模板:

// left,right指针分别指向窗口的左边与后边位置
// result用来保存计算的结果,该结果需要满足一定的条件
// baseResult用来保存需要求得的结果:最短的长度
初始化left,right, result, bestResult;

while(右指针没有到结尾){
    窗口扩大,加入right对应元素,更新当前result;
    while(result满足要求){
        更新最优结果bestResult;
        窗口缩小,移除left对应元素,left右移;
    }
    right++;
}

return bestResult;

三、例题1:长度最小的子数组

1️⃣题目描述

LeetCode209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105

2️⃣思想概述

  • 本题中需要满足的条件为:子数组的和 ≥ target;
  • 本题中需要求得的结果为:满足条件的子数组的最小长度。

有了这两个条件我们就可以套用寻找最短问题的模板来求解问题。

3️⃣代码实现

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int right = 0;
        int sum = 0;
        int minLength = Integer.MAX_VALUE;
        // 右指针没有到结尾
        while(right < nums.length){
            sum += nums[right];
            // sum满足条件,更新最优结果,并尝试向右移动left指针来缩小窗口
            while(sum >= target){
                minLength = Math.min(minLength, right - left + 1);
                sum -= nums[left];
                left++; 
            }
            right++;
        }
        return minLength == Integer.MAX_VALUE ? 0 : minLength;
    }
}

四、例题2:最小覆盖子串

上面的题目还是比较简单的,如果掌握了滑动窗口算法的话,下面我们来看一个困难级别的题目来体验一下。

1️⃣题目描述

LeetCode76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

示例 2:

输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。

示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

提示:

m == s.length
n == t.length
1 <= m, n <= 105
s 和 t 由英文字母组成

2️⃣思想概述

  • 本题中需要满足的条件为: 字符串s的子串能够涵盖字符串 t 中的所有字符;
  • 本题中需要求得的结果为:满足条件的最小子串。

有了这两个条件,通过套用寻找最短问题的模板来求解该问题也是没太大难度的。这题的难点在于我们如何来判断字符串s的某个子串能够涵盖字符串 t 中的所有字符。

我们可以用一个哈希表来表示字符串 t 中所有的字符以及它们出现的个数,用另外一个哈希表动态维护窗口中所有的字符以及它们出现的个数,如果这个动态表中包含 t 的哈希表中的所有字符,并且对应的个数都不小于 t 的哈希表中各个字符的个数,那么当前的窗口是可行的(对于该判断我们可以专门写一个方法来实现)。

3️⃣代码实现

class Solution {
    // 用来动态维护窗口中子串的所有字符以及它们出现的个数
    Map<Character,Integer> num_s = new HashMap<Character,Integer>();
    // 用来保存字符串 t 中所有的字符以及它们出现的个数
    Map<Character,Integer> num_t = new HashMap<Character,Integer>();
    public String minWindow(String s, String t) {
        // 先获取字符串 t 中所有的字符以及它们出现的个数
        for(int i = 0; i < t.length(); i++){
            char c = t.charAt(i);
            num_t.put(c, num_t.getOrDefault(c, 0) + 1);
        }
        int left = 0;
        int right = 0;
        int res_l=-1,res_r=-1;
        int minLength = Integer.MAX_VALUE;
        // 右指针没有到结尾
        while(right < s.length()){
            char c2 = s.charAt(right);
            if(num_t.containsKey(c2)){
                num_s.put(c2, num_s.getOrDefault(c2, 0) + 1);
            }
            // 判断当前的子串是否包含字符串t,满足条件的话,更新最优结果,并尝试向右移动left指针来缩小窗口
            while(check() && left <= right){
                if(right - left +1<minLength){
                    res_l = left;
                    res_r = right;
                    minLength = right - left +1;
                }
                char c3 = s.charAt(left);
                if(num_s.containsKey(c3)){
                    num_s.put(c3, num_s.getOrDefault(c3, 0) - 1);
                }
                left++;
            }
            right++;
        }
        
        if(minLength == Integer.MAX_VALUE){
            return "";
        }else{
            return s.substring(res_l, res_r+1);
        }
        // 上边这段代码的简写
        // return minLength == Integer.MAX_VALUE ? "" : s.substring(res_l, res_r+1);
        
    }

    // 用来判断某子串是否涵盖t中所有字符的方法
    public boolean check(){
        Iterator iter = num_t.entrySet().iterator();
        while(iter.hasNext()){
            Map.Entry entry = (Map.Entry) iter.next();
            Character key = (Character) entry.getKey();
            Integer val = (Integer) entry.getValue();
            if(num_s.getOrDefault(key, 0) < val){
                return false;
            }
        }
        return true;
    }

}

后记

本文为大家分享了 滑动窗口算法的思想,并且 为大家梳理了用滑动窗口算法解决问题的代码模板,最后通过两个经典例题(长度最小的子数组最小覆盖子串)来帮助大家更好的理解与掌握滑动窗口算法~

👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~

有关【LeetCode算法成长之路】滑动窗口算法总结与经典题目分析的更多相关文章

  1. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  2. 7个大一C语言必学的程序 / C语言经典代码大全 - 2

    嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来

  3. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  4. Hive SQL 五大经典面试题 - 2

    目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类

  5. Python 刷Leetcode题库,顺带学英语单词(31) - 2

    ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem

  6. ruby - (Ruby || Python) 窗口管理器 - 2

    我想用这两种语言中的任何一种(最好是ruby​​)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生

  7. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  8. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  9. 建模分析 | 平面2R机器人(二连杆)运动学与动力学建模(附Matlab仿真) - 2

    目录0专栏介绍1平面2R机器人概述2运动学建模2.1正运动学模型2.2逆运动学模型2.3机器人运动学仿真3动力学建模3.1计算动能3.2势能计算与动力学方程3.3动力学仿真0专栏介绍?附C++/Python/Matlab全套代码?课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。?详情:图解自动驾驶中的运动规划(MotionPlanning),附几十种规划算法1平面2R机器人概述如图1所示为本文的研究本体——平面2R机器人。对参数进行如下定义:机器人广义坐标

  10. 网站日志分析软件--让网站日志分析工作变得更简单 - 2

    网站的日志分析,是seo优化不可忽视的一门功课,但网站越大,每天产生的日志就越大,大站一天都可以产生几个G的网站日志,如果光靠肉眼去分析,那可能看到猴年马月都看不完,因此借助网站日志分析工具去分析网站日志,那将会使网站日志分析工作变得更简单。下面推荐两款网站日志分析软件。第一款:逆火网站日志分析器逆火网站日志分析器是一款功能全面的网站服务器日志分析软件。通过分析网站的日志文件,不仅能够精准的知道网站的访问量、网站的访问来源,网站的广告点击,访客的地区统计,搜索引擎关键字查询等,还能够一次性分析多个网站的日志文件,让你轻松管理网站。逆火网站日志分析器下载地址:https://pan.baidu.

随机推荐