【leetcode】滑动窗口专题

文章目录

  • 1.长度最小的子数组
  • 2.无重复字符的最长子串
  • 3.最大连续1的个数III
  • 4.将x减小到0的最小操作数
  • 5.水果成篮
  • 6.找到字符串中所有字母异位词
  • 7.串联所有单词的子串
  • 8.最小覆盖子串

在这里插入图片描述

1.长度最小的子数组

在这里插入图片描述
leetcode 209.长度最小的子数组

看到这个题目,第一眼肯定想到的是暴力枚举,那我们就来枚举以下试试:
在这里插入图片描述

很明显,暴力枚举的方式会超时。

在这里插入图片描述

那有没有哪里能优化一下,让它不超时呢?我们来分析一下:

在暴力枚举中,我们的 right 每次都会回到left位置的下一个,然后和 left 一起重新枚举。

在这里插入图片描述
优化枚举具体步骤如下:

在这里插入图片描述

在上面的枚举过程中,我们的蓝色框就像是一个滑动的、大小不固定的窗口,我们称这种方式叫做滑动窗口

对与滑动窗口而言,无非就以下几个步骤:
在这里插入图片描述
每个题目窗口的起始、更新结果的位置是不固定的,具体情况具体分析。

按照滑动窗口的方法,我们的代码就不会超时啦。
在这里插入图片描述
简单分析以下时间复杂度:从代码看好像是O(n2),但是由于我们滑动窗口的思想,两个指针是同向遍历,而且不会回退;当right指针结束时,循环结束,所以它的时间复杂度是O(n)。

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int ret = INT_MAX;int n = nums.size();int sum = 0;for(int left = 0, right = 0; right < n; right++)//right后移{//进窗口sum += nums[right];//判断窗口while(sum >= target){//符合条件,更新结果ret = min(ret,right - left + 1);sum -= nums[left];//出窗口left++;}  }if(ret == INT_MAX)return 0;elsereturn ret;}
};

2.无重复字符的最长子串

在这里插入图片描述
leetcode 3.无重复字符的最长字串

这一题首先想到的方法无疑就是枚举,然后统计每个字符出现的次数;如果一个字符出现了两次,那么当前字符对应的字符串就是最长子串
在这里插入图片描述
我们发现,暴力枚举法也可以过
在这里插入图片描述

那有没有更优的解法呢?我们来分析一下
在这里插入图片描述
上述解法不就是滑动窗口吗?
在这里插入图片描述

此时的时间复杂度O(n)是不是比暴力枚举O(n2)更加优秀了

class Solution {
public:int lengthOfLongestSubstring(string s) {int n = s.size();int hash[128] = { 0 };int ret = 0;for(int left = 0, right = 0; right < n; right++){hash[s[right]]++;//入窗口,先记录当前while(hash[s[right]] > 1)//若s[right]重复{hash[s[left]]--;//出窗口left++;}ret = max(ret,right - left + 1);//更新结果}return ret;}
};

3.最大连续1的个数III

在这里插入图片描述
leetcode 1004.最大连续1的个数III

分析题目可知,其中0可以翻转的意思就是:0可以当作1来用。那我们的目标就是找一段包含1的个数最大连续的区间,该区间中0的个数不可以超过k。

这一题的暴力枚举法就不演示了,我们直接上滑动窗口。
在这里插入图片描述
在这里插入图片描述
这样我们的代码就过咯
在这里插入图片描述

class Solution {
public:int longestOnes(vector<int>& nums, int k) {int n = nums.size();int zero = 0;//统计0的个数int ret = 0;for(int left = 0, right = 0; right < n; right++){//进窗口,判断是否是0if(nums[right] == 0)zero++;//判断0的个数是否大于kwhile(zero > k){//判断是否是0出窗口if(nums[left] == 0)zero--;left++;}//更新结果ret = max(ret,right-left+1);}return ret;}
};

4.将x减小到0的最小操作数

在这里插入图片描述
leetcode 1658.将x减小到0的最小操作数

通过读题我们可以发现,它一会是左边,一会是右边,是不是很难控制;那应该怎么做呢?
正难则反

  • 我们在数组中找一块连续的区间,数组中去除该连续区间的内容,剩下的内容刚好等于x时,那我们是不是就找到了一种情况
  • 该连续区间就是数组中元素的总和减去x
  • 当在数组中找到的一块连续区间最长时,我们就找到了最佳的解决方案。

在这里插入图片描述
还是像前面的题目一样,使用滑动窗口。

在这里插入图片描述

class Solution {
public:int minOperations(vector<int>& nums, int x) {int ret = 0;int total = 0;int n = nums.size();for(auto e : nums)total += e; //求数组的和int target = total - x; //target为要找的连续区间的总大小if(target < 0)//细节return -1;if(total == x)return n;int sum = 0;for(int left = 0, right = 0; right < n; right++){sum += nums[right];//进窗口while(sum > target){sum -= nums[left];left++;}if(sum == target)//找到目标区间,取长的一个ret = max(ret,right - left + 1);}if(ret == 0)return -1;elsereturn n - ret;}
};

5.水果成篮

在这里插入图片描述
leetcode 904.水果成篮

这个题目这么长,它表达的是什么意思呢?

只有两个篮子,篮子里的水果只能有两种,并且不能跨越树木,求你所经过的树的最多的个数。
那又是求一段连续区间的长度,我们可以使用滑动窗口

在这里插入图片描述
那我怎么知道当前摘的水果有几种呢?----使用哈希表统计
在这里插入图片描述
我们可以发现,使用哈希表的消耗还是挺大的,能不能再优化一下呢?

由题目要求可知,种类是小于105的,所以我们可以直接使用一个数组+一个变量(记录种类)
在这里插入图片描述

这样我们的效率就提升了很多。
在这里插入图片描述

class Solution {
public:int totalFruit(vector<int>& fruits) {int n = fruits.size();int ret = 0;int hash[100000] = { 0 };int kinds = 0;for(int left = 0, right = 0; right < n; right++){if(hash[fruits[right]] == 0)//判断是否是新种类水果kinds++;hash[fruits[right]]++;//进窗口while(kinds > 2)//判断总类是否大于2{hash[fruits[left]]--;//出窗口if(hash[fruits[left]] == 0)kinds--;  //去除该种类left++;}ret = max(ret,right - left + 1);}return ret;}
};

6.找到字符串中所有字母异位词

在这里插入图片描述

leetcode 438.找到字符串中所有字母异位词

分析题目可知,就是在s串中找出p串(p串中的字符顺序可打乱)。
那我们就可以找一个长度和p相等,且字符种类、个数和p串相等的子串即可

所以我们可以使用两个哈希表,分别统计p串和s串中字符的种类和个数。

那我们先使用暴力枚举的方式试一下:
在这里插入图片描述
在这里插入图片描述

那两个哈希表是如何进行比较的呢?

  1. 首先使用hash1记录p串中字符的类型个数
  2. 遍历s,找长度和p相等的子串,同时hash2存放当前字符
    a、若hash2[right] <= hash1[right]时,“有效字符”种类增加
    b、若hash2[right] > hash2[right],“有效字符”种类不变

在这里插入图片描述
暴力枚举的方式确实可以过,但效率比较低下。
既然是找一段连续的区间,那能不能使用滑动窗口呢?我们来试一下
在这里插入图片描述
这样我们的效率就高很多了
在这里插入图片描述

class Solution {
public:vector<int> findAnagrams(string s, string p) {vector<int> ret;int len = p.size();int hash1[128] = { 0 };for(auto e: p)hash1[e]++;//统计p串的种类int n = s.size();int hash2[128] = { 0 };//统计子串种类int kinds = 0;int tmp = 0;for(int left = 0,right = 0; right < n ; right++){hash2[s[right]]++; //进窗口tmp++;//子串长度增加if(hash2[s[right]] <= hash1[s[right]])kinds++;//"有效字符"种类增加if(tmp > len){if(hash2[s[left]] <= hash1[s[left]])kinds--;//left位置为“有效字符”,种类减少hash2[s[left]]--;tmp--;left++;}if(tmp == len)if(kinds == len)ret.push_back(left);}return ret;}
};

7.串联所有单词的子串

在这里插入图片描述

leetcode 30.串联所有单词的子串

这一题和前一道题目类似,只不过这里是将字符换成了字符串而已。因此我们还是使用:滑动窗口+哈希表的方式解决。
在这里插入图片描述

解题步骤:

  1. 先使用hash1统计words中字符串的种类
  2. 使用滑动窗口(由于字符串的长度是固定的,所以可以直接跳跃长度)
    a、定义起始:left、right
    b、字符串进窗口,需要使用字符串的函数substr进行裁剪
    c、判断字符串的种类
      是否出窗口
      更新结果

在这里插入图片描述
然而,代码只过了一部分,分析一下它的测试用例发现,
在这里插入图片描述
这样代码就过啦!

在这里插入图片描述

class Solution {
public:vector<int> findSubstring(string s, vector<string>& words) {vector<int> ret;unordered_map<string,int> hash1;for(auto& e : words)hash1[e]++;//统计要求的字符串种类int n = s.size();int len = words[0].size();//固定的字符串长度int m = words.size();//数组长度for(int i=0; i < len; i++){unordered_map<string,int> hash2;int count = 0;for(int left = i, right = i; right <= n -len; right+= len){string in = s.substr(right,len);//裁剪字符串hash2[in]++;//进窗口if(hash2[in] <= hash1[in])count++;//统计当前字符串数量if(right - left + 1 > m*len)//判断字符串数量是否大于字符数组{string out = s.substr(left,len);if(hash2[out] <= hash1[out])count--;hash2[out]--;//出窗口left += len;}if(count == m)ret.push_back(left);}}return ret;}
};

8.最小覆盖子串

在这里插入图片描述
leetcode 76.最小覆盖子串

该题和上一题的解题思路差不多,也是在s串中找t串的全部字符,只不过这里要将找到的字符串的最小的一个返回而已。

我们依旧使用滑动窗口+哈希表的方式解决。

  1. 使用hash1统计t串中字符的种类和数量
  2. 滑动窗口:定义起始位置 left, right
    a、进窗口
    b、判断是否出窗口
    c、更新结果(仅需记录串的起始位置和长度,最后在切割子串)

在这里插入图片描述

在代码中在记录字符串的起始位置和长度即可,这样我们的代码就过啦。

在这里插入图片描述

class Solution {
public:string minWindow(string s, string t) {int hash1[128] = { 0 };for(auto e : t)hash1[e]++;//统计t串的字符种类和数量int m = t.size();int n = s.size();int hash2[128] = { 0 };int count = 0;int start = 0;int len = INT_MAX;for(int left = 0, right = 0; right < n; right++){hash2[s[right]]++;//进窗口if(hash2[s[right]] <= hash1[s[right]])//是否更新有效字符count++;while(count >= m)//是否出窗口{if(count == m)//找到符合种类的子串{//取长度小的一个int curlen = right - left + 1;if(curlen < len){start = left;len = curlen;}}//出窗口if(hash2[s[left]] <= hash1[s[left]])count--;hash2[s[left]]--;left++;}}if(len == INT_MAX)return "";elsereturn s.substr(start,len);}
};

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

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

相关文章

科普文:深入理解Mybatis

概叙 (1) JDBC JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成.JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。 优点…

Vue3 + Echarts堆叠折线图的tooltip不显示问题

问题介绍 使用Echarts在Vue3Vite项目中绘制堆叠折线图的的时候&#xff0c;tooltip总是不显示&#xff0c;经过很长时间的排查和修改&#xff0c;最后发现是在使用上有错误导致的。 错误图片展示 问题原因 由于Vue3底层使用proxy代理创建示例&#xff0c;使用其创建出来的实…

FPGA-Verilog-Vivado-软件使用

这里写目录标题 1 软件配置2 FPGA-7000使用2.1 运行启动方式 1 软件配置 编辑器绑定为Vscode&#xff0c;粘贴VS code运行文件的目录&#xff0c;后缀参数保持不变&#xff1a; 如&#xff1a; D:/Users/xdwu/AppData/Local/Programs/Microsoft VS Code/Code.exe [file name]…

(19)夹钳(用于送货)

文章目录 前言 1 常见的抓手参数 2 参数说明 前言 Copter 支持许多不同的抓取器&#xff0c;这对送货应用和落瓶很有用。 按照下面的链接&#xff08;或侧边栏&#xff09;&#xff0c;根据你的设置了解配置信息。 Electro Permanent Magnet v3 (EPMv3)Electro Permanent M…

职业教育人工智能实验实训室建设应用案例

随着人工智能技术的快速发展&#xff0c;其在职业教育领域的应用逐渐深入。唯众作为一家专注于教育技术领域的企业&#xff0c;积极响应国家关于人工智能教育的政策号召&#xff0c;通过建设人工智能实验实训室&#xff0c;为学生提供了一个实践操作与创新思维相结合的学习平台…

34 超级数据查看器 关联图片

超级数据查看器app&#xff08;excel工具&#xff0c;数据库软件&#xff0c;表格app&#xff09; 关联图片讲解 点击 打开该讲的视频 点击访问app下载页面 豌豆荚 下载地址 大家好&#xff0c;今天我们讲一下超级数据查看器的关联图片功能 这个功能能让表中的每一条信息&…

数据结构-散列表(hash table)

6.1 散列表的概念 散列表又叫哈希&#xff08;hash&#xff09;表&#xff0c;是根据键&#xff08;key&#xff09;直接访问在内存存储位置的值&#xff08;value&#xff09;的数据结构&#xff0c;由数组演化而来&#xff08;根据数组支持按照下标进行随机访问数据的特性&a…

力扣爆刷第163天之TOP100五连刷81-85(回文链表、路径和、最长重复子数组)

力扣爆刷第163天之TOP100五连刷81-85&#xff08;回文链表、路径和、最长重复子数组&#xff09; 文章目录 力扣爆刷第163天之TOP100五连刷81-85&#xff08;回文链表、路径和、最长重复子数组&#xff09;一、234. 回文链表二、112. 路径总和三、169. 多数元素四、662. 二叉树…

Python高级(三)_正则表达式

Python高级-正则表达式 第三章 正则表达式 在开发中会有大量的字符串处理工作,其中经常会涉及到字符串格式的校验。 1、正则表达式概述 正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、…

PostgreSql中的JSON数据类型

PostgreSQL 提供了两种 JSON 数据类型&#xff1a;JSON 以及 JSONB。这两种类型主要的区别在于数据存储格式&#xff0c;JSONB 使用二进制格式存储数据&#xff0c;更易于处理。 PostgreSQL 推荐优先选择 JSONB 数据类型。 两种数据类型之间的区别&#xff1a; 功能JSONJSONB存…

网络建设与运维23国赛网络运维正式赛题解析

竞赛环境请看主页&#xff01; 23国赛网络运维 任务描述&#xff1a;某集团公司在更新设备后&#xff0c;路由之间无法正常通信&#xff0c;请修 复网络达到正常通信。 &#xff08;1&#xff09; 请在server1“管理员”下拉菜单中选择“镜像”选项卡&#xff0c;点 击 “创…

超声波眼镜清洗机有用吗?四大主流超声波清洗机品牌整理测评

长期佩戴的眼镜&#xff0c;若不定期清洗&#xff0c;不仅镜片会逐渐积聚油脂、灰尘&#xff0c;影响透光率&#xff0c;使视物模糊&#xff0c;更严重的是&#xff0c;眼镜上日益增加的微小杂质和细菌可能会逐渐影响到眼睛健康&#xff0c;导致视力下降、眼部疾病等问题。 这…

Go 1.19.4 函数-Day 08

1. 函数概念和调用原理 1.1 基本介绍 函数是基本的代码块&#xff0c;用于执行一个任务。 Go 语言最少有个 main() 函数。 你可以通过函数来划分不同功能&#xff0c;逻辑上每个函数执行的是指定的任务。 函数声明告诉了编译器函数的名称&#xff0c;返回类型&#xff0c;和参…

STM32 - PWR 笔记

PWR&#xff08;Power Control&#xff09;电源控制 PWR 负责管理 STM32 内部的电源供电部分&#xff0c;可以实现 可编程电压监测器 和 低功耗模式 的功能 可编程电压监测器&#xff08;PVD&#xff09;可以监控VDD电源电压&#xff0c;当VDD下降到PVD阀值以下或上升到PVD…

usbserver工程师手记(三)手工开通 OTP功能

1、设定密钥&#xff0c;用户自行选择一个密钥&#xff0c;以下以密钥为 EAZAYOKNGETBOPC5 为例说明 2、usb server 配置otp 密钥&#xff0c;目前还没有UI 界面开通&#xff0c;后续版本会支持从管理界面开通 curl -X POST -H Content-Type: application/json -H Accept: app…

Centos7下zabbix安装与部署

Centos7下zabbix安装与部署 一、Zabbix介绍 1、zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案 2、zabbix能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各…

活动策划秘籍:如何让企业活动引爆市场?

作为一个活动策划&#xff0c;我的经验是&#xff0c;活动策划是一场精心编排的交响乐&#xff0c;每一个音符都要恰到好处。 想要做好企业活动策划工作的关键在于综合考虑多个方面&#xff0c;并确保每个环节的顺畅执行。 以下是7个关键要素&#xff0c;只要用心体会&#x…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【密钥派生(C/C++)】

密钥派生(C/C) 以HKDF256密钥为例&#xff0c;完成密钥派生。具体的场景介绍及支持的算法规格&#xff0c;请参考[密钥生成支持的算法]。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生成密钥 指定密钥别名。 初始化密钥属…

通过电压差判定无源晶振是否起振正确吗?

在电子工程中&#xff0c;无源晶振作为许多数字电路的基础组件&#xff0c;其是否成功起振对于系统的正常运行至关重要。然而&#xff0c;通过简单检测晶振两端的电压差来判断晶振是否工作&#xff0c;这一方法存在一定的误区&#xff0c;晶发电子将深入探讨这一话题&#xff0…

2008年下半年软件设计师【下午题】真题及答案

文章目录 2008年下半年软件设计师下午题--真题2008年下半年软件设计师下午题--答案 2008年下半年软件设计师下午题–真题 2008年下半年软件设计师下午题–答案