详解顺序结构滑动窗口处理算法

🎀个人主页: https://zhangxiaoshu.blog.csdn.net
📢欢迎大家:关注🔍+点赞👍+评论📝+收藏⭐️,如有错误敬请指正!
💕未来很长,值得我们全力奔赴更美好的生活!

前言

在数据结构和算法方面的面试中,数组和字符串的相关问题往往是一个重要的考察点。面试官通常会测试面试者在处理这些基础数据结构时的熟练程度,因为这直接关系到解决实际问题的能力。在数组和字符串的考察中,双指针和滑动窗口以及排序算法、字符串的处理API成为关键技巧,本文主要对滑动窗口进行简单介绍。


文章目录

  • 前言
  • 1. 序
  • 2. 滑动窗口原理
  • 3. 应用场景
    • (1)长度最小的子数组
    • (2)无重复字符的最长子串
    • (3)存在重复元素 II
  • 总结


1. 序

双指针和滑动窗口是在处理数组和字符串问题时常用的技巧。双指针通常用于解决数组中的一些查找或判断问题,通过设置两个指针在数组上移动,实现对数组的遍历和比较。滑动窗口则常用于解决字符串中的子串或子数组问题,通过维护一个可变大小的窗口在字符串上滑动,从而实现对子串或子数组的探测。

排序算法在面试中同样是一个重要的考察点,因为它与数组相关,对数据的整理和查找提供了基础。熟练掌握常见的排序算法,如快速排序、归并排序等,有助于在解决各种问题时更高效地处理数组。此外,对于字符串的处理API也是面试中需要掌握的知识。熟悉字符串的各种操作,如查找子串、替换字符、反转字符串等,能够帮助面试者更灵活地处理字符串相关的问题。

本文主要是对滑动窗口这种常用技巧进行简要介绍,帮助读者在面对数组和字符串相关问题时能够更加从容应对。深入理解这些技巧,并在实际问题中灵活运用,将有助于提高面试者在数据结构和算法面试中的表现。

2. 滑动窗口原理

滑动窗口法是一种在处理数组或字符串的子序列(子数组或子串)问题时常用的技巧。它通过维护一个动态的窗口来解决问题,窗口的起始和结束位置会根据问题的要求进行滑动。这种方法通常用于求解最长子串、最短子数组等问题。

在这里插入图片描述

基本思路:

  1. 初始化窗口的起始位置和结束位置。通常使用两个指针,比如 start 和 end,表示窗口的左右边界。

  2. 通过移动窗口的结束位置,扩大窗口。根据问题的要求,可以通过增加 end 指针的位置来扩展窗口。

  3. 通过移动窗口的起始位置,缩小窗口。当窗口包含的元素满足某个条件时,可以通过增加 start 指针的位置来缩小窗口。

  4. 重复以上步骤直到满足问题的条件。 在每一步中,都可以根据问题的要求更新窗口的状态,并在遍历完整个数组或字符串后得到问题的解。

滑动窗口法的优势在于它能够在线性时间内解决很多子序列问题,而无需使用额外的空间。这使得它在处理大规模数据时表现良好。

3. 应用场景

(1)长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

具体思路如下:

  • 初始化变量 ans 为整数的最大值 Integer.MAX_VALUE,start 和 end 分别表示当前子数组的起始和结束位置,sum 表示当前子数组的和。

  • 使用 while 循环遍历数组 nums,其中 end 指针负责扩大窗口,start 指针负责缩小窗口。

  • 在循环中,先将当前元素加到 sum 中,然后检查是否满足 sum >= target 的条件。如果满足,说明当前窗口的子数组和大于等于目标值,此时进入内部的 while 循环。

  • 在内部的 while 循环中,不断缩小窗口,即通过减去 nums[start] 的值来减小 sum。同时,更新 ans 为当前窗口的长度 end - start + 1 和 ans 之前值的较小值。这样,通过不断缩小窗口,可以找到满足条件的最小子数组。

  • 重复上述过程,直到 end 指针遍历完整个数组。

  • 返回最终结果 ans,如果 ans 仍然为 Integer.MAX_VALUE,说明没有找到满足条件的子数组,返回 0;否则,返回找到的最小子数组的长度。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {

        int ans = Integer.MAX_VALUE;
        int start = 0, end = 0;
        int sum = 0;

        while(end < nums.length){
            sum += nums[end];
            while(sum >= target){
                sum-=nums[start];
                ans = Math.min(ans,end-start+1);
                start++;
            }
            end++;
        }
        return ans== Integer.MAX_VALUE ? 0 : ans;
    }
}

(2)无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

具体思路如下:

  • 初始化指针和数据结构: 使用 start 和 end 两个指针来表示当前子串的起始和结束位置,使用 HashSet 来存储当前子串中出现的字符。lenMax 用于记录最长不含重复字符的子串长度。

  • 滑动窗口: 通过不断移动 end 指针,扩大窗口。当遇到重复字符时,开始缩小窗口。

  • 处理重复字符:如果当前字符是新字符,将其添加到 set 中,然后更新 lenMax 为当前子串的长度(end - start + 1)的最大值。如果当前字符已经在 set 中,表示有重复字符,需要将 start 指针右移,并将对应的字符从 set 中移除,直到子串中不再包含重复字符。

  • 遍历完整个字符串: 通过不断移动 end 指针和更新 lenMax,直到 end 指针遍历完整个字符串。

  • 返回结果: 返回最终的 lenMax,即最长不含重复字符的子串的长度。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int start=0;
        int end=0;

        HashSet<Character> set = new HashSet<Character>();

        int lenMax=0;

        while(end < s.length()){          
            if(set.add(s.charAt(end))){
                lenMax=Math.max(lenMax,end-start+1);
                end++;      
            }else{
               set.remove(s.charAt(start));
               start++;
           }
        }
        return lenMax;
    }
}

(3)存在重复元素 II

给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。
输入:nums = [1,2,3,1], k = 3
输出:true

  • 初始化数据结构: 使用一个 LinkedHashSet 来存储当前窗口中的元素,保持插入顺序。

  • 遍历数组: 使用两个指针 start 和 end 遍历数组,其中 end 指针负责扩大窗口,start 指针负责缩小窗口。

  • 判断重复元素: 在每一步中,首先检查当前窗口中是否包含数组中的元素 nums[end]。如果存在,表示存在重复元素,直接返回 true。

  • 保持窗口大小: 在窗口大小达到 k 之后,通过缩小窗口,即移除 set 中的元素 nums[start],并将 start 指针右移。

  • 遍历完整个数组: 重复上述步骤,直到 end 指针遍历完整个数组。

  • 返回结果: 如果在遍历过程中未找到重复元素,返回 false。

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        int numLength = nums.length;
        Set<Integer> set = new LinkedHashSet<>();
        for(int start = 0, end = 0; end < numLength; end++){
            if(set.contains(nums[end])){
                return true;
            }
            set.add(nums[end]);
            while (end - start >= k){
                set.remove(nums[start]);
                start++;
            }
        }
        return false;
    }
}

总结

滑动窗口算法是一种用于解决数组或字符串中子序列(子数组或子串)问题的有效技巧。它通过维护一个动态的窗口,不断调整窗口的起始和结束位置,以满足问题的条件。以下是滑动窗口算法的关键特点、优势和应用场景:

  1. 关键特点:
  • 使用两个指针(通常是起始指针和结束指针)表示窗口的边界。
  • 通过不断移动窗口的边界,动态调整窗口的大小。
  • 用于解决需要求解子序列最优解的问题。
  1. 优势:
  • 高效: 滑动窗口算法通常具有线性时间复杂度,因为每个元素或字符只需被访问一次。
  • 空间效率: 使用常数级的额外空间,不需要存储整个子序列的信息,而是通过维护窗口的边界来解决问题。
  • 简洁: 算法思路相对简单,易于理解和实现。
  1. 应用场景:
  • 最长子串或子数组: 用于求解最长不含重复字符的子串、最短子数组等问题。
  • 满足条件的子串: 用于找到满足特定条件的子串,如包含指定字符、和大于等于某个值的子数组等。
  • 窗口内的统计信息: 用于在移动窗口的过程中动态计算窗口内元素的统计信息,如和、平均值等。
  • 固定长度的窗口: 用于处理固定长度的窗口,例如计算滑动窗口的平均值。
  1. 注意事项:
  • 确保窗口的起始和结束位置的移动是合理的,避免重复计算和漏算。
  • 处理窗口的边界条件,确保不越界。

总体来说,滑动窗口算法是一种高效、简洁的解决子序列问题的方法,在处理字符串和数组等数据结构时广泛应用。

文中有不对的地方欢迎指正、补充。

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

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

相关文章

WPF 附加属性+控件模板,完成自定义控件。建议观看HandyControl源码

文章目录 相关连接前言需要实现的效果附加属性添加附加属性&#xff0c;以Test修改FontSize为例依赖属性使用触发器使用直接操控 结论 控件模板&#xff0c;在HandyControl的基础上面进行修改参考HandyControl的源码控件模板原型控件模板 控件模板触发器完整样式简单使用 结论 …

光学3D表面轮廓仪微纳米三维形貌一键测量

光学3D表面轮廓仪(白光干涉仪)利用白光干涉原理&#xff0c;以0.1nm分辨率精准捕捉物体的表面细节&#xff0c;实现三维显微成像测量&#xff0c;被广泛应用于材料学领域的研究和应用。 了解工作原理与技术 材料学领域中的光学3D表面轮廓仪&#xff0c;也被称为白光干涉仪&am…

低价对品牌渠道的危害

品牌价值的体现主要在价格&#xff0c;比如要与竞品体现差异&#xff0c;除了产品功能上有做出差异&#xff0c;价格上也需要设置不同的阶梯&#xff0c;但如果经销商不遵守这个体系&#xff0c;或者非授权店铺随意低价&#xff0c;对于品牌来说都是非常不好的事情&#xff0c;…

Django后台管理(二)

一、自定义注册管理类介绍 官网:Django 管理站点 | Django 文档 | Django 注册模型除了使用 Django 默认的管理类admin,也可以自定义,比如: class StudentAdmin(admin.ModelAdmin):pass admin.site.register(Student, StudentAdmin)ModelAdmin 类是管理界面中模型的表示。…

微信小程序 wxs内联与外联的写法

内联写法 <!-- 内联wxs --> <view>大写字母{{m1.toUpper("xmly")}}</view> <wxs module"m1">module.exports.toUpperfunction(str){return str.toUpperCase()} </wxs> 外联写法 新建一个wxs文件 写一个函数&#xff0c;将…

架构(十五)Java字节码增强

一、引言 一般如果需要做增强类的架构工具会使用SpringBoot提供的切面&#xff0c;但是这逃不开两个问题&#xff1a;1、使用方需要加注解代码&#xff1b;2、版本更新导致的发布。 所以java还提供了字节码层面的增强方案&#xff0c;对使用的系统是无感的。 二、字节码增强选…

BLEU: a Method for Automatic Evaluation of Machine Translation

文章目录 BLEU: a Method for Automatic Evaluation of Machine Translation背景和意义技术原理考虑 n n n - gram中 n 1 n1 n1 的情况考虑 n n n - gram中 n > 1 n\gt 1 n>1 的情况考虑在文本中的评估初步实验评估和结论统一不同 n n n 值下的评估数值考虑句子长度…

Ubuntu上Jenkins自动化部署Gitee上SpringBoot项目

文章目录 安装安装JDK安装Maven安装GitNodeJS安装&#xff08;可选&#xff09;安装Jenkins 配置Jenkins为Jenkins更换插件源设置jenkins时区安装插件全局工具配置添加Gitee凭证Gitee项目配置 部署后端1.新建任务2.配置源码管理3.构建触发器4.到Gitee中添加WebHook5.构建环境6.…

C++——基础语法(3):内联函数、auto关键字、基于范围的for循环、空指针nullptr

6. 内联函数 在函数前加入inline修饰即可将函数变为内联函数。所谓内联函数&#xff0c;就是在编译时C编译器会将函数体在调用内联函数的地方展开&#xff0c;从而省去了调用函数的栈帧开销&#xff0c;提高程序运行效率。 inline int Add(int a, int b) {return a b; } int …

十一、计算机视觉-膨胀操作

文章目录 前言一、什么是膨胀二、膨胀操作的实现1.引入库 三、膨胀的原理 前言 上节我们学习了腐蚀操作&#xff0c;本节我们讲一下膨胀操作&#xff0c;膨胀和腐蚀实际上是相反的操作。上节我们把云峰这2个字周围没用的像素去掉了&#xff0c;但是云峰这2个字也变细了&#x…

Protocol Buffer-nanopb介绍

文章目录 一、需求二、环境三、相关概念3.1 protocol buffer介绍3.2 nanopb&#xff08;支持C语言&#xff09;3.3 proto文件 四、proto基本语法4.1 proto文件的定义4.2 字段规则4.3 字段类型4.4 字段编号4.5 proto语法4.6 进阶语法4.6.1 message嵌套4.6.2 enum关键字4.6.3 one…

【Flink精讲】Flink状态及Checkpoint调优

RocksDB大状态调优 RocksDB 是基于 LSM Tree 实现的&#xff08;类似 HBase&#xff09; &#xff0c;写数据都是先缓存到内存中&#xff0c; 所以 RocksDB 的写请求效率比较高。 RocksDB 使用内存结合磁盘的方式来存储数据&#xff0c;每 次获取数据时&#xff0c;先从内存中 …

什么是高可用架构

一、什么是高可用 在运维中&#xff0c;经常听到高可用&#xff0c;那么什么是高可用架构呢&#xff1f;通俗点讲&#xff0c;高可用就是在服务故障&#xff0c;节点宕机的情况下&#xff0c;业务能够保证不中断&#xff0c;服务正常运行。 举个例子&#xff0c;支付宝&#…

GS069——直流有刷电机调速电路 通过外接电阻网络,改变与之相接的 VMOS 管的输出,达到控制电动工具 转速的作用。 功耗小,电源电压范围宽。

GS069电动工具直流调速电路是CMOS专用集成电路&#xff0c;具有电源电压范 围宽、功耗小、抗干扰能力强等特点。通过外接电阻网络&#xff0c;改变与之相接 的VMOS 管的输出&#xff0c;达到控制电动工具转速的作用。该电路输出幅值宽&#xff0c; 频率变化小&#xff0c;占空比…

vue ts html 中如何遍历 Enum 类型构建页面结构

vue ts html 中如何遍历 Enum 类型构建页面结构 一、需求 定义了一个 Enum 用来标记菜单类型&#xff1a; enum EnumMenuType {目录 1,菜单,按钮,外链 }你得 Enum 知道它的序号是随第一个定义的值自动增长的 现在想在 ElementUI 界面的 radio-group 中遍历它&#xff0c;…

聚集高速托盘类四向穿梭车ASRV|一车跑全仓可获得10000个货位的HEGERLS智能搬运机器人

随着国内外制造业加速转型升级&#xff0c;越来越多的企业需要进行物流智能化升级&#xff0c;但是往往受到仓库面积、高度、形状等现实条件的限制&#xff0c;以及市场不确定性因素的影响。因此&#xff0c;相对于投资传统的自动化立体库&#xff0c;企业更倾向于选择智能化、…

HarmonyOS—低代码开发Demo示例

接下来为大家展示一个低代码开发的JS工程的Demo示例&#xff0c;使用低代码开发如下华为手机介绍列表的HarmonyOS应用/服务示例。 1.删除模板页面中的控件后&#xff0c;选中组件栏中的List组件&#xff0c;将其拖至中央画布区域&#xff0c;松开鼠标&#xff0c;实现一个List组…

[设计模式Java实现附plantuml源码~行为型] 撤销功能的实现——备忘录模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

formality:set_constant应用

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 往期文章链接: formality:形式验证流程 scan mode func的功能检查需要把scan mode设置成0。