【滑动窗口】C++高效解决子数组问题

个人主页 : zxctscl
专栏 【C++】、 【C语言】、 【Linux】、 【数据结构】、 【算法】
如有转载请先通知

文章目录

  • 前言
  • 1 209. 长度最小的子数组
    • 1.1 分析
    • 1.2 代码
  • 2 3. 无重复字符的最长子串
    • 2.1 分析
    • 2.2 代码
  • 3 1004. 最大连续1的个数 III
    • 3.1 分析
    • 3.2 代码
  • 4 1658. 将 x 减到 0 的最小操作数
    • 4.1 分析
    • 4.2 代码
  • 5 904. 水果成篮
    • 5.1 分析
    • 5.2 代码
  • 6 438. 找到字符串中所有字母异位词
    • 6.1 分析
    • 6.2 代码
  • 7 30. 串联所有单词的子串
    • 7.1 分析
    • 7.2 代码
  • 8 76. 最小覆盖子串
    • 8.1 分析
    • 8.2 代码

前言

1 209. 长度最小的子数组

在这里插入图片描述

1.1 分析

暴力枚举出所有的子数组和,发现可以利用双指针来解决。
这里双指针是同向的,就能优化为滑动窗口。
(1)先初始化left和right,用left和right来标记这个窗口的左右区间
(2)进窗口
(3)判断决定是否出窗口

1.2 代码

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

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

在这里插入图片描述

2.1 分析

暴力枚举利用双指针加哈希表:
left在起始位置,right遍历,当字符不在哈希表里,就添加;当字符在时候,right就停止遍历,把此时的字符长度更新一下;再把left移动到与right遍历到相同字符的那个位置的后面一个,然后right再继续移动。
在这里插入图片描述
使用滑动窗口来实现:

(1)先初始化left和right,用left和right来标记这个窗口的左右区间
(2)进窗口,让字符进入哈希表
(3)判断:当窗口内出现重复字符出窗口,再从哈希表中删除该字符。
再更新长度

2.2 代码

class Solution 
{
public:int lengthOfLongestSubstring(string s) {int hash[128]={0};//数组模拟哈希表int n=s.size();int ret=0;for(int left=0,right=0;right<n;right++){hash[s[right]]++;//进窗口while(hash[s[right]]>1)//判断{hash[s[left++]]--;//出窗口}ret=max(ret,right-left+1);}return ret;}
};

3 1004. 最大连续1的个数 III

在这里插入图片描述

3.1 分析

只要翻转的0个数小于等于k就行。
如果按照题目要求翻转,是比较麻烦的,但可以等价处理为:找一个区间满足0的次数不超过k就行。
也就是找出最长子数组,这个子数组的0不超过k个
解法一:暴力枚举所有子数组,加上一个计数器zero
优化一下

固定left,right向后移动,right遇到0统计一个计数器,计数器等于3时候,停止枚举,就是这个区间最优解。

在这里插入图片描述
利用滑动窗口来解决问题:

  1. 先定义两个指针left=0,right=0
  2. 进窗口,如果right遇到1,无视;遇到0,zero+1
  3. 判断:zero>k 就 出窗口
    判断完后更新结果

3.2 代码

class Solution {
public:int longestOnes(vector<int>& nums, int k) {int ret=0;for(int left=0,right=0,zero=0;right<nums.size();right++){if(nums[right]==0)zero++;while(zero>k)if(nums[left++]==0)zero--;   ret=max(ret,right-left+1);}return ret;}
};

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

在这里插入图片描述

4.1 分析

发现既有左边删除,又有右边的的,不好操作,此时可以找一个连续区域,恰好所有元素的和(sum)等于sum-x

  1. 先定义两个指针left=0,right=0
  2. 进窗口,sum+=nums[right]
  3. 判断:sum>target
    出窗口:sum-=nums[left]
    当sum==target判断完后更新结果

4.2 代码

class Solution {
public:int minOperations(vector<int>& nums, int x) {int sum=0;for(int a:nums)sum+=a;int target=sum-x;if(target<0)return -1;int ret=-1;for(int left=0,right=0,tmp=0;right<nums.size();right++){tmp+=nums[right];while(tmp>target){tmp-=nums[left++];}if(tmp==target)ret=max(ret,right-left+1);}if(ret==-1)return -1;else{return nums.size()-ret;}}
};

5 904. 水果成篮

在这里插入图片描述

5.1 分析

题目意思就是:找出一个最长子数组,子数组中不超过两种类型的水果。

解法一:暴力枚举+哈希表:从某一个位置开始,建立一个哈希表,暴力枚举时候,遍历一个放哈希表一个,当表中数据超过2时候,就出现了多余水果,前面的区间就是最优解。

优化:固定一个位置left,right遍历数组放在哈希表中,直到某一个位置,right再向右遍历时候,水果种类就超过2,此时这段区间就是最优解。此时,当left向后移动一位时,种类数目(kinds)可能会出现两种情况:(1)kinds不变,那么right也不变;(2)kinds变小,此时right就可以向右移动

解法二:滑动窗口

  1. 先定义两个指针left=0,right=0
  2. 进窗口,遍历数组放哈希表里,哈希表里面放水果种类及对应数量
  3. 判断:如果哈希表长度大于2而且它对应数量为0时候就出窗口
    更新结果
    在这里插入图片描述

5.2 代码

class Solution {
public:int totalFruit(vector<int>& fruits){int hash[100001]={0};int ret=0;for(int left=0,right=0,kinds=0;right<fruits.size();right++){if(hash[fruits[right]]==0)kinds++;hash[fruits[right]]++;while(kinds>2){hash[fruits[left]]--;if(hash[fruits[left]]==0)kinds--;left++;}ret=max(ret,right-left+1);}return ret;}
};

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

在这里插入图片描述

6.1 分析

如何快速判断两个字符串是否是异位词?
两个字符串的构成是一样的,利用哈希表,遍历两个字符串分别放在哈希表中,对比两个哈希表中字符出现的个数是否相等就行,相等就是,反之就不是。

算法:
暴力+哈希表
把p字符串先放入哈希表中,再到s中找相等长度的区间子串放在另一个哈希表中,比较一个,相等就把起始位置放在结果中。

当s中与p等长区间中比较后,不是异位词,此时就把s放在哈希表中的第一个字符删除,再加上区间长度下一个位置字符就行。
在这里插入图片描述

p长度为m,hash1记录p的字符情况,hash2记录s中一段区间的字符情况
滑动窗口+哈希表

  1. 先定义两个指针left=0,right=0
  2. 进窗口,(哈希表遍历s)hash2[in]++
  3. 判断:right-left+1>m,就出窗口,再hash1[out]–(对应s中的字符得删除)

当两个哈希表里面存在信息是否一致时候,就更新结果
在这里插入图片描述
优化:更新判断条件
利用变量count来统计窗口中有效字符的个数
right遍历时候,c加入哈希表2中,与hash1中c个数相比较,都是1,此时count=1
right继续向后面移动,遇到c加入hash2中,这个时候hash2中c=2,,比hash1中c=1大,这个时候count不更新
right继续向后移动,b放入hash2中,比较hash1中b=1,此时count=2,而且s遍历的区间长度等于p的长度,此时有效字符个数count=2不等于p的长度;
right继续右移,这是区间长度大于p的,left就右移,a放到哈希表2中a=1,count=3,删除c(hash2中c=2,删除的这个c是无效字符),hash2中c=1;
在这里插入图片描述
进窗口:进窗口后比较hash2[in]<=hash1[in]此时count++;
出窗口:出去前 hash2[out]<=hash1[out]此时count–;
更新结果:count=m

6.2 代码

class Solution {
public:vector<int> findAnagrams(string s, string p) {vector<int> ret;int hash1[26]={0};//统计pfor(auto x:p)hash1[x-'a']++;int hash2[26]={0};//sint m=p.size();for(int left=0,right=0,count=0;right<s.size();right++){char in=s[right];hash2[in-'a']++;if(hash2[in-'a']<=hash1[in-'a'])count++;if(right-left+1>m){char out=s[left++];if(hash2[out-'a']<=hash1[out-'a'])count--;hash2[out-'a']--;}if(count==m)ret.push_back(left);}return ret;}
};

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

在这里插入图片描述

7.1 分析

与上面串联所有单词的子串类似,只不过把字符换成字符串,解法类似。
把题目给的words中的字符串看做一个一个整体,像下面这样
在这里插入图片描述

与上面不同的是:
(1)哈希表:不能向上面一样用数组来实现,这里存字符串,得用unordered_map<string,int> hash
(2)left与right指针的移动:移动的步长是单词的长度(len)
(3)滑动窗口指向的次数:单词可能是从s的第一个位置开始划分,也可能是第二个位置,也可能是第三个位置:
在这里插入图片描述
滑动窗口执行len次

7.2 代码

class Solution {
public:vector<int> findSubstring(string s, vector<string>& words) {vector<int> ret;unordered_map<string,int> hash1;for(auto& x:words)hash1[x]++;int len=words[0].size(),m=words.size();for(int i=0;i<len;i++){unordered_map<string,int> hash2;for(int left=i,right=i,count=0;right+len<=s.size();right+=len){string in=s.substr(right,len);//进窗口+维护counthash2[in]++;if(hash2[in]<=hash1[in])count++;//判断if(right-left+1>len*m){//出窗口+维护countstring 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 76. 最小覆盖子串

在这里插入图片描述

8.1 分析

与串联所有单词的子串类似,

解法一:暴力枚举+哈希表
在连续区间中找符合要求的ABC出现次数
在这里插入图片描述
在符合连续区间中,left右移right会出现两种情况
在这里插入图片描述

解法二:滑动窗口

  1. 先定义两个指针left=0,right=0
  2. 进窗口,hash2[in]++
  3. 判断:对比一下hash2有效字符大于等于hash1有效字符就更新结果起始位置,最短长度;再出窗口,hash2[out]–

优化:利用变量count来统计窗口中有效字符的种类
(1).进窗口 进之后当hash2[in]==hash1[in]此时count++
(2) 出窗口 出之前,当hash2[out]==hash1[out]count--
(3)判断 count==hash.size()

8.2 代码

class Solution {
public:string minWindow(string s, string t) {int hash1[128]={0};int kinds=0;//统计有效字符有多少种for(auto& x:t){if(hash1[x]==0) kinds++;hash1[x]++;}int hash2[128]={0};int minlen=INT_MAX,begin=-1;for(int left=0,right=0,count=0;right<s.size();right++){char in=s[right];hash2[in]++;if(hash2[in]==hash1[in])count++;//进窗口+维护countwhile(kinds==count){if(right-left+1<minlen){minlen=right-left+1;begin=left;}char out=s[left++];if(hash2[out]--==hash1[out])count--;}}if(begin==-1)return "";else return s.substr(begin,minlen);}
};

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

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

相关文章

[rStar] 搜索代理(MCTS/束搜索)

第2章&#xff1a;搜索代理(MCTS/束搜索) 欢迎回到rStar 在前一章中&#xff0c;我们学习了求解协调器&#xff0c;它就像是解决数学问题的项目经理。 它组织整个过程&#xff0c;但本身并不进行"思考"&#xff0c;而是将这项工作委托给其专家团队。 今天&#x…

Electron 核心模块速查表

为了更全面地覆盖常用 API&#xff0c;以下表格补充了更多实用方法和场景化示例&#xff0c;同时保持格式清晰易读。 一、主进程模块 模块名核心用途关键用法 示例注意事项app应用生命周期管理• 退出应用&#xff1a;app.quit()• 重启应用&#xff1a;app.relaunch() 后需…

Qt C++ 图形绘制完全指南:从基础到进阶实战

Qt C 图形绘制完全指南&#xff1a;从基础到进阶实战 前言 Qt框架提供了强大的2D图形绘制能力&#xff0c;通过QPainter类及其相关组件&#xff0c;开发者可以轻松实现各种复杂的图形绘制需求。本文将系统介绍Qt图形绘制的核心技术&#xff0c;并通过实例代码演示各种绘制技巧…

二分搜索边界问题

在使用二分搜索的时候&#xff0c;更新条件不总是相同&#xff0c;虽然说使用bS目的就是为了target&#xff0c;但也有如下几种情况&#xff1a;求第一个target的索引求第一个>target的索引求第一个>target的索引求最后一个target的索引求最后一个<target的索引求最后…

【springboot+vue3】博客论坛管理系统(源码+文档+调试+基础修改+答疑)

目录 一、整体目录&#xff1a; 项目包含源码、调试、修改教程、调试教程、讲解视频、开发文档&#xff08;项目摘要、前言、技术介绍、可行性分析、流程图、结构图、ER属性图、数据库表结构信息、功能介绍、测试致谢等约1万字&#xff09; 二、运行截图 三、代码部分&…

20250907_梳理异地备份每日自动巡检Python脚本逻辑流程+安装Python+PyCharm+配置自动运行

一、逻辑流程(autocheckbackup.py在做什么) 1.连接Linux服务器 用 paramiko 登录你配置的 Linux 服务器(10.1.3.15, 10.1.3.26),进入指定目录(如 /home, /backup/mes),递归列出文件。 采集到的信息:服务器IP、目录、数据库名称、文件名、大小、修改时间。 2.连接Wind…

terraform-state详解

一、Treeaform-state的作用 Terraform-state是指Terroform的状态&#xff0c;是terraform不可缺少的生命周期元素。本质上来讲&#xff0c;terraform状态是你的基础设施配置的元数据存储库&#xff0c;terraform会把它管理的资源状态保存在一个状态文件里。 默认情况下&#xf…

四、kubernetes 1.29 之 Pod 生命周期

一、概述当容器与 pause 容器共享网络&#xff08;Network&#xff09;、IPC&#xff08;进程间通信&#xff09;和 PID&#xff08;进程命名空间&#xff09;后&#xff0c;二者形成了一种紧密的 "共享命名空间" 关系&#xff0c;共同构成了 Kubernetes 中 "Po…

AI与环保:礼貌用语背后的能源挑战与解决方案

程序员的技术管理推荐阅读 窄化效应&#xff1a;程序员与管理者的隐形情绪陷阱 从“激励”到“保健”&#xff1a;80后与90后程序员&#xff0c;到底想要什么&#xff1f; 从“激励”到“保健”&#xff1a;80后与90后程序员&#xff0c;到底想要什么&#xff1f; 场景引入&…

OpenCV C++ 特征提取:从角点检测到对象识别

特征提取是计算机视觉的核心技术,通过识别图像中具有代表性的关键点及其描述信息,实现图像匹配、对象识别、姿态估计等高级任务。本章将系统讲解从基础的图像金字塔、角点检测,到复杂的 ORB 和 SIFT 特征提取与匹配,最终实现基于特征的对象检测完整流程。 一、图像金字塔 …

Codeforces Round 1049 (Div. 2) D题题解记录

大致题意&#xff1a;给定nnn个区间(li,ri)(l_i,r_i)(li​,ri​)。每次选取两个尚未被标记的区间(l1,r1)(l_1,r_1)(l1​,r1​)与(l2,r2)(l_2,r_2)(l2​,r2​)&#xff0c;使得他们均被标记&#xff0c;同时可以任选x∈[l1,r1]&#xff0c;y∈[l2,r2]x\in[l_1,r_1]&#xff0c;y…

《WINDOWS 环境下32位汇编语言程序设计》第15章 注册表和INI文件

15.1 注册表和INI文件简介在一个操作系统中&#xff0c;无论是操作系统本身还是运行于其中的大部分应用程序&#xff0c;都需要使用某种方式保存配置信息。在DOS系统中&#xff0c;配置信息往往是软件的开发者根据自己的喜好用各种途径加以保存的&#xff0c;比如在磁盘上面写一…

JDK 17、OpenJDK 17、Oracle JDK 17 的说明

Java生态系统的核心概念&#xff1a;简单来说&#xff1a;JDK 17 是一个标准规范&#xff0c;定义了Java开发工具包第17个长期支持版应该包含什么功能。openjdk-17-jdk 是一个具体的实现&#xff0c;是遵循上述规范、由OpenJDK社区提供的开源软件包。下面我们通过一个表格和详细…

手写MyBatis第58弹:如何优雅输出可执行的SQL语句--深入理解MyBatis日志机制:

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…

Spring Boot 监控实战:集成 Prometheus 与 Grafana,打造全方位监控体系

前言 在当今微服务架构盛行的时代&#xff0c;应用程序的监控变得尤为重要。Spring Boot 作为广泛使用的微服务框架&#xff0c;其监控需求也日益增加。Prometheus 和 Grafana 作为开源监控领域的佼佼者&#xff0c;为 Spring Boot 应用提供了强大的监控能力。本文将详细介绍如…

JS中的多线程——Web Worker

众所周知&#xff0c;JavaScript 是单线程运行的&#xff08;至于为什么是单线程可以看一下这篇文章——事件循环机制&#xff09;&#xff0c;当浏览器主线程被大量计算任务阻塞时&#xff0c;页面就会出现明显的卡顿现象。Web Worker 提供了在独立线程中运行 JavaScript 的能…

【SQL注入】延时盲注

sleep(n)​​: 核心延时函数。使数据库程序暂停 n秒。​​if(condition, true_expr, false_expr)​​: 条件判断函数。如果 condition为真&#xff0c;执行 true_expr&#xff0c;否则执行 false_expr。​​用于将延时与判断条件绑定​​。​​mid(a, b, c)​​: 字符串截取函数…

IntelliJ IDEA 2025.1 Java Stream Debugger 快速使用指南

1. 功能概览 Java Stream Debugger 提供 Trace Current Stream Chain 功能&#xff0c;用来在调试时分析和可视化 Stream 操作链。 主要用途&#xff1a; 在运行时查看流操作链的每一步输出找出 map/filter 等操作的问题避免手动加 peek() 打印调试2. 使用入口 在 IDEA 2025.1 …

ARM-指令集全解析:从基础到高阶应用

一、ARM 指令集体系结构版本ARM 公司定义了多个指令集版本&#xff1a;ARMv1&#xff1a;原型机 ARM1&#xff0c;没有用于商业产品。ARMv2&#xff1a;扩展 V1&#xff0c;包含 32 位乘法指令和协处理器指令。ARMv3&#xff1a;第一个微处理器 ARM6 核心&#xff0c;支持 Cach…

第3讲 机器学习入门指南

近年来&#xff0c;随着企业和个人生成的数据量呈指数级增长&#xff0c;机器学习已成为日益重要的技术领域。从自动驾驶汽车到流媒体平台的个性化推荐&#xff0c;机器学习算法已广泛应用于各个场景。让我们深入解析机器学习的核心要义。3.1 机器学习定义机器学习是人工智能的…