滑动窗口篇: 长度最小子数组|无重复字符最长字串

目录

1、滑动窗口算法

1.1 核心概念

1.2 基本步骤

1.3 应用场景

1.4 优势

2. leetcode 209 长度最小子数组

暴力解题思路:

滑动窗口思路:

3、无重复字符的最长子串

暴力解题思路: 

滑动窗口思路:


1、滑动窗口算法

        滑动窗口算法是一种在处理数组、字符串或其他序列数据结构时非常有用的技巧,特别适用于寻找特定条件的连续子序列问题。这种算法通过维护一个可变的“窗口”,在序列上滑动来高效地解决问题。

        使用滑动窗口通常会用到双指针,我们在前面也讲解过双指针,可以参考双指针算法篇:两数之和 、三数之和

1.1 核心概念

窗口:想象一个可以在序列上左右移动的窗口,窗口内的元素是我们关注的对象。

双指针通常使用两个指针(左指针和右指针)来表示窗口的边界。左指针代表窗口的起始位置,右指针代表窗口的结束位置。

动态调整:根据问题需求,窗口的大小可能固定也可能变化,通过移动左右指针来调整窗口覆盖的范围。

1.2 基本步骤

  1. 初始化:设置左指针 left 和右指针 right 初始位置,通常从序列的起始位置开始。根据问题可能还需要初始化一些状态变量,比如窗口内元素的和、计数器等。
  2. 扩展窗口:逐步将右指针向右移动,每次移动都检查新增元素是否满足问题条件,同时更新窗口内的相关信息(如总和、最大值、最小值等)。
  3. 收缩窗口:当窗口满足某个终止条件时(如总和达到了目标值、找到了所需子序列等),开始考虑缩小窗口。通过移动左指针来排除窗口左侧的元素,同时保持窗口内信息的更新。
  4. 重复步骤2和3:在序列未完全探索之前,持续执行扩展和收缩窗口的操作。
  5. 结果处理:根据问题需求,在算法执行过程中或结束后处理并返回最终结果。

1.3 应用场景

最大/最小子数组和:找到数组中和最大的(或最小的)连续子数组。

无重复字符的最长子串:在字符串中寻找不含重复字符的最长子串。

子数组问题:如找到和大于等于特定值的最小子数组长度。

字符串匹配:如寻找包含所有字母的最小子串等。

1.4 优势

效率:将原本可能需要嵌套循环的问题简化为单层循环,显著提高了算法的时间复杂度,通常达到O(n)级别。

灵活性:适用于多种类型的问题,只需适当调整窗口的扩展和收缩条件。

2. leetcode 209 长度最小子数组

题目描述

给定一个含有 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. 双重循环:外层循环遍历数组的每个起始位置,内层循环尝试以该位置为起点的所有可能的子数组。
  2. 计算子数组和:对每个子数组,累加其元素和。
  3. 判断与更新:如果当前子数组的和达到或超过目标值,就比较并更新最小长度。
  4. 结果处理:如果最小长度仍为初始值(即大于数组长度),说明没有找到符合条件的子数组,返回0;否则返回找到的最小长度。

代码示例:

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int n = nums.size();if (n == 0) return 0;// 初始化结果为不可能的情况,即比数组长度还大1int minLength = n + 1;// 双重循环,枚举所有子数组for (int start = 0; start < n; ++start) {int sum = 0;for (int end = start; end < n; ++end) {sum += nums[end]; // 计算当前子数组的和// 如果当前子数组和大于等于目标值,更新最短长度if (sum >= target) {minLength = min(minLength, end - start + 1);break; // 找到一个满足条件的子数组后,提前结束内层循环}}}// 如果没有找到满足条件的子数组,返回0;否则返回找到的最短长度return minLength == n + 1 ? 0 : minLength;}
};

时间复杂度较高,为O(n^2),在数据规模较大时效率低下,不适用于性能敏感的场景。相比滑动窗口算法的线性时间复杂度O(n),暴力解法在效率上明显不足。

暴力解法虽然思路简单,但是效率低下,在这个题目要求下会超时,暴力是将所有子数组列举一遍,但是比如start到end间的数据已经计算过一次了,再计算就没有必要了,所以只需要在sum中减去nums[left],left++即可。

滑动窗口思路:

  1. 初始化:

    • 初始化两个指针 left 和 right,均从0开始。
    • 初始化 sum(当前窗口内元素的和)为0,ret(记录满足条件的最短子数组长度,默认极大值INT_MAX)。
  2. 双指针遍历:

    • 使用 right 指针遍历数组,将新元素加入窗口和 sum 中。(进窗口)
  3. 窗口内求解:(循环)

    • 当窗口内元素和 sum 大于等于目标值 target 时:
      • 更新 ret 的值为当前子数组长度(right-left+1)和原 ret 中的较小值。
      • 然后从窗口(即从 sum 中)移除左侧元素(nums[left]),并将 left 指针右移一位,继续寻找可能更小的满足条件的子数组。(出窗口)
  4. 循环结束处理:

    • 遍历结束后,若 ret 仍为初始值 INT_MAX,说明没有找到符合条件的子数组,返回0;否则返回 ret

代码示例: 

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int sum=0;int ret=INT_MAX;for(int left=0,right=0;right<nums.size();right++){sum+=nums[right];while(sum>=target){ret=min(ret,right-left+1);sum-=nums[left];left++;}}return ret==INT_MAX?0:ret;}
};

滑动窗口简化了循环,时间效率上提示了很多,不会超时。

3、无重复字符的最长子串

题目描述

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

 示例:

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"是一个子序列,不是子串。

暴力解题思路: 

  1. 双重循环:外层循环遍历字符串的每个字符作为子串的起始点,内层循环尝试以该字符为起点的后续所有字符作为子串的一部分。
  2. 无重复检查:使用unordered_set来存储当前子串中的字符,以检查是否有重复。一旦发现重复字符,立即停止对该起始位置的进一步扩展,并检查下一个起始位置。
  3. 更新最大长度:在每次内循环结束时,用当前无重复子串的长度更新最长无重复子串的长度。

代码示例:

class Solution {
public:int lengthOfLongestSubstring(string s) {int n = s.length();int maxLength = 0; // 用于记录最长无重复子串的长度// 枚举所有可能的子串起始位置for (int i = 0; i < n; ++i) {unordered_set<char> charSet; // 用于检查当前子串是否有重复字符int uniqueLength = 0; // 记录当前子串的长度// 枚举以i为起始的子串的结束位置jfor (int j = i; j < n; ++j) {// 如果当前字符不在charSet中,说明是新的唯一字符if (charSet.find(s[j]) == charSet.end()) {charSet.insert(s[j]);uniqueLength++; // 子串长度增加} else {// 如果当前字符已经出现过,则停止当前子串的检查break;}}// 更新最大无重复子串长度maxLength = max(maxLength, uniqueLength);}return maxLength;}
};

暴力解法虽然勉强跑过了,但还是效率比较低。

滑动窗口思路:

  1. 初始化:

    • 定义变量 ret 用来记录最长子串长度,初始化为0。
    • 获取字符串长度 n
    • 初始化一个大小为128的整型数组 hash 用于记录ASCII表中每个字符出现的次数(假设字符串只包含ASCII字符)。
  2. 双指针遍历:

    • 使用 left 和 right 分别作为窗口的左右边界,初始时都指向字符串的起始位置。
    • right 向右移动,遍历整个字符串。
  3. 字符计数与窗口调整:

    • 每遇到一个字符,就在 hash 表中对应字符的计数加一。(进窗口)hash[s[right]]++;
    • 当 hash[s[right]] 大于1(循环),说明当前字符在窗口内有重复,这时需要移动 left 指针来缩小窗口,直到窗口内没有重复字符。同时,hash[s[left]] - -,并将 left 向右移动。(出窗口)
  4. 更新最长子串长度:

    在每次窗口调整后(即窗口内无重复字符时),用 right-left+1 计算当前无重复子串的长度,并用 max() 函数更新全局最长子串长度 ret
  5. 返回结果:

    遍历结束后,返回最长无重复字符子串的长度 ret

代码示例:

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

滑动窗口简化了循环,通过巧妙地控制窗口的扩张与收缩来高效地找到满足条件的最长子串,相较于暴力解法,其时间复杂度大大降低至O(n)。

两者可能相似,取决于具体实现。暴力解法可能会使用额外的数据结构(如哈希表)来辅助检查,滑动窗口同样可能使用哈希表来跟踪窗口内的元素,但整体上,滑动窗口的空间复杂度一般更为可控且高效,因为它不需要存储所有可能的子序列。

暴力解法:通常具有较高的时间复杂度,例如在解决“寻找字符串中无重复字符的最长子串”问题时,暴力解法的时间复杂度为O(n^2),因为它需要对每个子串进行检查,而子串数量是n(n+1)/2。

暴力解法在数据规模较小时可能尚可接受,但在面对大规模数据集时,其效率低下,难以在有限时间内得到结果。

滑动窗口:时间复杂度通常为O(n),这是因为滑动窗口算法只需要遍历一次输入序列。通过动态调整窗口的大小,它能够高效地找到满足条件的子序列,避免了冗余的检查。

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

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

相关文章

while 习题

while 结构 习题 1.计算1到100所有整数和 2.提示用户输入一个小于100的整数&#xff0c;并计算从1到该数之间所有整数的和 3.求从1到100所有整数的偶数和、奇数和 echo -e \n 可以实现换行 4.用户输入密码&#xff0c;脚本判断密码是否正确&#xff0c;正确密码为123456&am…

基于Laravel 10 + Vue(scui) + MySQL的快速开发的后台管理系统

​ 系统介绍 ​基于Laravel 10 Vue(scui) MySQL的快速开发的后台管理系统 版权申明 禁止将本产品用于含诈骗、赌博、色情、木马、病毒等违法违规业务使用。 代码仓库 gitee地址&#xff1a; 基础版本 内置模块 用户管理&#xff1a;用于维护管理系统的用户&#xff0c…

笔记---DFS,深度优先搜索

深度优先搜索乃是注重深度&#xff0c;会把一条路径优先全部搜完然后再去回溯&#xff0c;再去搜其他路径 连通性模型 与BFS中的Flood Fill相似 AcWing.1112.迷宫 一天Extense在森林里探险的时候不小心走入了一个迷宫&#xff0c;迷宫可以看成是由 n∗n 的格点组成&#xff…

Python GraphQL服务器实现库之tartiflette使用详解

概要 Tartiflette是一个为Python编写的GraphQL服务器实现,它建立在现代异步编程库如asyncio之上,提供了高性能的GraphQL执行环境。Tartiflette专注于提供最佳的开发者体验,支持最新的GraphQL特性。 安装 安装Tartiflette相对简单,但需要依赖于一些系统级的库。 首先,需…

css定位+精灵图

一、定位 在CSS中&#xff0c;定位&#xff08;Positioning&#xff09;是一种布局技术&#xff0c;用于控制HTML元素在页面上的确切位置。CSS提供了几种不同的定位方案&#xff0c;每种方案都有其特定的用途和行为。以下是CSS中几种主要的定位方法&#xff1a; 静态定位&…

龙芯LA架构相关的存储管理

&#xff08;LoongArch-P92&#xff09; 目录 1.1 物理地址空间 1.2 虚拟地址空间 1.3 LA64架构下的虚拟地址缩减模式 1.4 存储访问类型 1.5 页表映射存储管理 1.5.1 TLB组织结构 1.5.2 基于TLB的虚实地址转换过程 1.5.3 TLB的软件管理 &#xff08;1&#xff09;…

开源高性能的分布式时序数据库:Lindb

Lindb&#xff1a;为大数据时代量身打造的高性能时序数据库&#xff0c;让海量数据存储与实时分析触手可及。- 精选真开源&#xff0c;释放新价值。 概览 Lindb 是一款开源的分布式时序数据库&#xff0c;它以其高性能和可伸缩性在海量数据存储及快速查询计算方面展现出独特的…

9.多数元素

文章目录 题目简介题目解答解法一&#xff1a;排序代码&#xff1a;复杂度分析&#xff1a; 解法二&#xff1a;摩尔投票法代码&#xff1a;复杂度分析&#xff1a; 解法三&#xff1a;哈希表代码复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来…

#兼职副业赚钱吗?# 宝妈与上班族在水牛社的财富探索

在这个繁忙的都市节奏中&#xff0c;宝妈与上班族都面临着平衡家庭与经济的挑战。那么&#xff0c;兼职副业真的能为他们带来额外的收入吗&#xff1f;接下来&#xff0c;让我们通过两个实例&#xff0c;揭示宝妈和上班族是如何在水牛社找到兼职副业赚钱的契机的。 ✨ 宝妈的故…

Linux 进程信号【信号产生】

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux知识分享⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; 目录 前言 信号概念 1. 生活角度的信号 2…

线性代数的一些理解(更新中)

以前学的时候都是囫囵吞枣&#xff0c;能搞过就得了。现在有了点时间可以静下来看看。。 还是分成点来看吧。 1 小车运行 一个车匀速在一维坐标前行&#xff0c;速度是2米每秒&#xff0c;起始点是0。如何描述 设 &#x1d465;(&#x1d461;) 表示车辆在时间 &#x1d461…

【JavaScript】内置对象 - 数组对象 ③ ( 数组反转 - reverse 方法 | 数组排序 - sort 方法 | 自定义数组排序规则 )

文章目录 一、数组排序1、翻转数组元素 - reverse()2、数组元素排序 - sort() 默认从小到大排序3、数组元素排序 - sort() 自定义排序规则4、数组元素排序 - sort() 自定义降序排序简化写法 Array 数组对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript…

关于 vs2019 c++ 20规范,STL 库提供的标准分配器 alloctor 及其 traits 及涉及分配器交换的全局函数 _Pocs

(1) 我们写 c 代码&#xff0c;使用 STL 库中的模板&#xff0c;很少自己写对象的分配器。用 STL 中的分配器也够用。研究 STL 中的分配器也可以为咱们自己写分配器提供参考。 咱们会遇到这样的场景&#xff0c;例如交换两个容器对象&#xff1a; list a ,b ; a .swap (b) ; 这…

深入理解Java TreeSet:实现与使用案例分析

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

如何使用 ERNIE 千帆大模型基于 Flask 搭建智能英语能力评测对话网页机器人(详细教程)

ERNIE 千帆大模型 ERNIE-3.5是一款基于深度学习技术构建的高效语言模型&#xff0c;其强大的综合能力使其在中文应用方面表现出色。相较于其他模型&#xff0c;如微软的ChatGPT&#xff0c;ERNIE-3.5不仅综合能力更强&#xff0c;而且在训练与推理效率上也更高。这使得ERNIE-3…

idea-自我常见配置

1. 主题配置 2. 显示方法分隔符 Editor->General->Appearance 3. 忽略大小写提示 Editor->General->Code Completion 4. 自动导包 Editor->general->Auto Import 5. 取消单行显示Tabs Editor->General->Editor Tabs 效果如下图&#xff1a; 6. 设置…

2024中国大学排名爬取

在pycharm中编写如下代码&#xff1a; import requests from bs4 import BeautifulSoup import bs4 import re def getHTMLText(url):try:r requests.get(url,timeout 30)r.raise_for_status()r.encoding r.apparent_encodingreturn r.textexcept:return ""def r…

ctfshow web入门 php反序列化 web267--web270

web267 查看源代码发现这三个页面 然后发现登录页面直接admin/admin登录成功 然后看到了 ///backdoor/shell unserialize(base64_decode($_GET[code]))EXP <?php namespace yii\rest{class IndexAction{public $checkAccess;public $id;public function __construct(){…

【半夜学习MySQL】库的操作(含库的创建、删除、修改、备份操作/查看mysql连接情况/字符集和校验规则详谈)

&#x1f3e0;关于专栏&#xff1a;半夜学习MySQL专栏用于记录MySQL数据相关内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 创建数据库字符集和校验规则查看字符集合校验规则校验规则对数据库的影响 操纵数据库数据备份和恢复查看连接情况 创建数据库…

6.数据库

1.实体用矩形表示&#xff0c;属性用椭圆表示&#xff0c;联系用菱形表示 2.层次模型用数表示 3.网状模型用图结构表示 4.关系模型用二维表格结构来表示 5.概念模式基本表 外模式视图 内模式存储 6.模式/内模式映像 外模式/模式映像 7.数据的物理独立性 跟内模式关系 逻辑是视图…