滑动窗口(C++)

文章目录

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


通常,算法的主体说明会放在第一道题中。但实际上,不通常。

算法在代码上的体现不是一道题能全部看出来的。

1、长度最小的子数组

链接

在这里插入图片描述

窗口其实就是指一块区间,用一些条件限制住的一个区间,比如数组某两个位置之间就是一个窗口。

暴力解法就是找到所有子数组,找到最小长度。那么优化一下,定义两个变量ab,ab都指向数组第一个元素,然后加上此时的数,b往后走一步,a固定住。也就是说a固定一个数,b在之后的所有数中找达到条件的连续子数组。b每走一步,就加上当前的值。满足条件时,b就可以不动了,此时b停在最后一个相加的数。由于都是正整数,b往后继续走也肯定会满足条件,而题目要求找最小长度,所以就没必要继续走了。此时以a代表的值为开头的连续数组就找到了,计算它的长度,保存下来。

a往后走一步,此时b可以继续不动,因为相对于上一个连续数组,我们已经计算了和的值,那么减去开头的值就是现在ab所限制的区间的总和,如果不符合条件,b就继续往后走。

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

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

链接

在这里插入图片描述

暴力解法就是找到所有的子串,得到最大值,当然遇到有重复的就不能继续了。如何找重复,如果是Python,可以用in来判断,不过C++就用哈希就好,每次开始一个子串的逐个判断时,就创建一个哈希表,把每个字符都放进去,这样有重复的就可以判断出来了。

优化暴力解法。当遇到重复时,就从下一个字符又开始计算,但有可能重复的字符在原本的子串的第4个位置,那么不如找到原子串中重复字符的位置,从这个位置的下一个位置开始再继续判断子串,这样就减少了一些步骤。

当窗口内有重复字符时再出窗口,找到重复字符在原子串位置的下一个位置;判断重复用哈希表。

class Solution {
public:int lengthOfLongestSubstring(string s) {int hash[128] = {0};int n = s.size(), len = 0;int r = 0, l = 0;while(r < n){hash[s[r]]++;while(hash[s[r]] > 1) //有重复了, 该出窗口hash[s[l++]]--;len = max(len, r - l + 1);r++;}return len;}
};

3、最大连续1的个数 Ⅲ

链接

在这里插入图片描述

暴力解法很简单,就是依次枚举即可。

优化暴力解法。滑动窗口的主要思路就是如何进窗口和出窗口。如果遇到1就可以继续往后走,遇到0就用一个计数器,让计数器加1,直到大于k时就出窗口。下一次进窗口时,起始位置就得变更。

class Solution {
public:int longestOnes(vector<int>& nums, int k) {int n = nums.size();int l = 0, r = 0, zero = 0, ret = 0;while(r < n){if(nums[r] == 0) zero++;while(zero > k)if(nums[l++] == 0) zero--; //不仅出窗口, 也同时让l往后走以及把zero归0ret = max(ret, r - l + 1);r++;}return ret;}
};

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

链接

在这里插入图片描述

如果按照题目给的定义去做,会发现要如何选择被删的数比较麻烦。不如换个思路,抛开左或右边的数不谈,如果要符合要求,那么去除左或右边的数,剩下的数就应当等于sum - x。所以现在的思路就是找到一个最长的子数组,所以它肯定连续,让其总和等于sum - x。

让sum - x = target。先从头开始,依次加上每个值,直到加上某个值后正好 >= target,也就是没加之前总和是小于target的,这时候指向区间右端的指针right就不需要动了,因为根据提示,每个数都大于0,所以再往后走就肯定是大于target了。到达这个位置,指向区间左端的指针left就应该往后走。这时候right不需要动,因为right之前的区间肯定小于target,而left后移一步,就更小了,或许这时候left和right规定的区间的数的总和就等于target了。

那么进窗口就是让right往后走,并且加上当前的值;出窗口就是在区间总和大于target时,就出,不判断等于是因为我们要求最终要等于,如果等于也要跳,就控不住了;当总和等于target时就更新结果。

class Solution {
public:int minOperations(vector<int>& nums, int x) {int n = nums.size();int l = 0, r = 0, tmp = 0, res = -1;int sum = 0;for (int e : nums) sum += e;int target = sum - x;if(target < 0) return -1; //先总体判断一下while(r < n){tmp += nums[r];while(tmp > target)tmp -= nums[l++];if(tmp == target)res = max(res, r - l + 1);r++;}if(res == -1) return res;else return n - res;}
};

5、水果成篮

链接

在这里插入图片描述
在这里插入图片描述

仔细看题就能明白题意。本质上就是找出一个最长的子数组,数组中的数不超过2种。

暴力解法中要控制种类数量不超过2,可以建立哈希表,当第3种进入哈希表时就停止操作。

优化暴力解法。当遇到第3种出现时,也就是right指针指向第3种类型时,就停止,然后left往后移一步,移到left和right之间的区间只有两种数时才停止,然后接着right再继续往后走,去检查是否有第3种类型出现。

代码中做了一些优化。k表示种类。

class Solution {
public:int totalFruit(vector<int>& f) {int hash[100001] = {0};int n = f.size();int l = 0, r = 0, res = 0;int k = 0;while(r < n){if(hash[f[r]] == 0) ++k;++hash[f[r]];while(k > 2){--hash[f[l]];if(hash[f[l]] == 0) --k;++l;}res = max(res, r - l + 1);++r;}return res; }
};

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

链接

在这里插入图片描述

此题往后的三道题一脉相承。

对于如何判断异位词,我们可以用两个哈希表,只要相同的字符出现的次数相同即可,只要有一个不同就不行。按照暴力解法,根据p字符串的长度,从s的开头开始找,每次都找p长度个,然后比较;接着从下一个字符开始再找并比较。

优化暴力解法。按照暴力解法,比如cbae,如果要3个字符,就能有两个选择,cba,bae。两者只有一个字符的不同,所以不如在更换区间时,指向区间左右端的left和right指针都往后走一步即可,不需要让right从left下一个字符处再去判断。另一个角度理解就是,比如p长度是3,当right走到了第四个字符时,让left往后移一步,这样就是下一个3个字符区间。

对于哈希表判断,可以建一个26大小的哈希表,但应当优化一下,利用变量count来统计窗口中有效字符的个数。s和p对比,可能出现p中c字符出现1次,但是s中某个区间c字符出现2次。剩下的看代码。

class Solution {
public:vector<int> findAnagrams(string s, string p) {vector<int> res;int hash1[26] = {0};for(auto ch : p) hash1[ch - 'a']++;int hash2[26]{0};int m = p.size();int l = 0, r = 0, n  = s.size(), count = 0;while(r < n){char in = s[r];if(++hash2[in - 'a'] <= hash1[in - 'a']) ++count;if(r - l + 1 > m){char out = s[l++];if(hash2[out - 'a']-- <= hash1[out - 'a']) --count;}//在r和l之间的区间有3个数时, 如果符合要求就会push进去, 此时count=m//当更换一个区间后, 更换之前count就已经计入了第m + 1个数, 所以这里当去掉一个数后也可以判断if(count == m) res.push_back(l);++r;}return res;}
};

7、串联所有单词的子串

链接

在这里插入图片描述
在这里插入图片描述

此题和前后两道一脉相承。

和上一题相似,把异位词改成单词就行。但还有点不一样。上一题是滑动窗口 + 哈希表,这里也是。这道题中,移动的步长应当和words中字符串长度相同,不过从一个单词的每一个字符处开始滑动窗口,进行多次;哈希表是<string, int>。

直接看代码。

class Solution {
public:vector<int> findSubstring(string s, vector<string>& words) {vector<int> res;unordered_map<string, int> hash1;for(auto& e: words) hash1[e]++;int len = words[0].size(), m = words.size();for(int i = 0; i < len; ++i){unordered_map<string, int> hash2;for(int l = i, r = i, count = 0; r + len <= s.size(); r += len){string in = s.substr(r, len);hash2[in]++;if(hash1.count(in) && hash2[in] <= hash1[in]) count++;if(r - l + 1 > len * m){string out = s.substr(l, len);if(hash1.count(out) && hash2[out] <= hash1[out]) count--;hash2[out]--;l += len;}if(count == m) res.push_back(l);}}return res;}
};

8、最小覆盖子串

链接

在这里插入图片描述
在这里插入图片描述

此题和前面两道一脉相承。

暴力解法就是挨个字符作为开头去判断。并且从上面的那些题来看,判断是否包含用哈希表就好。哈希表中要求的那些字符的对应的数字大于等于t中的才行,所以s和t各有一个哈希表。

当一个区间符合要求后,指向区间左端的指针left向后移一步,指向右端的指针right先不动,判断现在的这个区间是否符合要求,如果不符合right再往后走继续判断。

所以进窗口就是让s的字符在哈希表中的数值增加,hash2[in]++;要出窗口前,判断是否符合要求,要出就hash2[out]–。in是right指向,out是left指向的。在出之前,判断之后,更新结果。

优化一下,也是之前题的思路,用一个变量count来标记有效字符的种类。进窗口时,hash2[in] 等于hash1[in],count就++;出窗口之前,hash2[out] 等于 hash1[out]时,count就–。判断条件就是count是否等于hash1.size()。count为什么要这样更改?仔细想想s对应的hash1中某个字符出现的次数多的话如何应对?

看代码

class Solution {
public:string minWindow(string s, string t) {int hash1[128] = {0};int k = 0; //统计t中的有效字符for(auto ch : t)if(hash1[ch]++ == 0) ++k;int hash2[128] = {0};int min = INT_MAX, begin = -1;for(int l = 0, r = 0, count = 0; r < s.size(); ++r){char in = s[r];if(++hash2[in] == hash1[in]) ++count;while(count == k) //开始判断{if(r - l + 1 < min){min = r - l + 1;begin = l;}char out = s[l++];if(hash2[out]-- == hash1[out]) --count;}}if(begin == -1) return "";else return s.substr(begin, min);}
};

结束。

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

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

相关文章

gradle构建工具

setting.gradle // settings.gradle rootProject.name my-project // 指定根项目名称include subproject1, subproject2 // 指定子项目名称&#xff0c;可选jar包名称 方式一 jar {archiveBaseName my-application // 设置 JAR 文件的基本名称archiveVersion 1.0 // 设置…

重载赋值运算符

c编译器可能会给类添加四个函数 1默认构造函数 2默认析构函数 3默认拷贝构造函数&#xff0c;对成员变量进行浅拷贝。 4默认赋值函数&#xff0c;队成员变量进行浅拷贝。 #include<iostream> using namespace std; class CGirl { public:int m_bh;string m_name;voi…

【VUE基础】VUE3第三节—核心语法之computed、watch、watcheffect

computed 接受一个 getter 函数&#xff0c;返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。 创建一个只读的计算属性 ref&#xff1a; <template><div cl…

3033.力扣每日一题7/5 Java

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;算法练习关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 思路 解题方法 时间复杂度 空间复杂度 Code 思路 首先创建一个与…

【C++】unordered系列容器的封装

你很自由 充满了无限可能 这是很棒的事 我衷心祈祷你可以相信自己 无悔地燃烧自己的人生 -- 东野圭吾 《解忧杂货店》 unordered系列的封装 1 unordered_map 和 unordered_set2 改造哈希桶2.1 模版参数2.2 加入迭代器 3 上层封装3.1 unordered_set3.2 unordered_map 4 面…

基于springboot的工作绩效管理系统的设计与实现+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

零基础学习MySQL---库的相关操作

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、创建数据库 1.语法 CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] .…

Android 简单快速实现 下弧形刻度尺(滑动事件)

效果图&#xff1a; 直接上代码&#xff1a; package com.my.view;import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Pai…

WordPress付费进群V2主题,多种引流方法,引私域二次变现

全新前端UI界面&#xff0c;多种前端交互特效让页面不再单调&#xff0c;进群页面群成员数&#xff0c;群成员头像名称&#xff0c;每次刷新页面随机更新不重复&#xff0c;最下面评论和点赞也是如此随机刷新不重复 进群页面简介&#xff0c;群聊名称&#xff0c;群内展示&…

UML2.0-系统架构师(二十四)

1、&#xff08;重点&#xff09;系统&#xff08;&#xff09;在规定时间内和规定条件下能有效实现规定功能的能力。它不仅取决于规定的使用条件等因素&#xff0c;还与设计技术有关。 A可靠性 B可用性 C可测试性 D可理解性 解析&#xff1a; 可靠性&#xff1a;规定时间…

ServiceImpl中的参数封装为Map到Mapper.java中查询

ServiceImpl中的参数封装为Map到Mapper.java中查询&#xff0c;可以直接从map中获取到key对应的value

论文阅读【时间序列】DSformer

论文阅读【时间序列】DSformer arxive: DSformer: A Double Sampling Transformer for Multivariate Time Series Long-term Prediction github: MTST 分类&#xff1a;多变量时间序列&#xff08;Multivariate time series&#xff09; 核心观点 多变量时间序列3个维度信息 …

Android AlertDialog对话框

目录 AlertDialog对话框普通对话框单选框多选框自定义框 AlertDialog对话框 部分节选自博主编《Android应用开发项目式教程》&#xff08;机械工业出版社&#xff09;2024.6 在Android中&#xff0c;AlertDialog弹出对话框用于显示一些重要信息或者需要用户交互的内容。 弹出…

【Linux进阶】磁盘分区2——MBR和GPT

1.磁盘的分区 因为如果你的磁盘被划分成两个分区&#xff0c;那么每个分区的设备文件名是什么&#xff1f; 在了解这个问题之前&#xff0c;我们先来复习一下磁盘的组成&#xff0c;因为现今磁盘的划分与它物理的组成很有关系。 我们谈过磁盘主要由碟片、机械手臂、磁头与主轴马…

gda动态调试-cnblog

忽的发现gda有动态调试功能 动态监听返回值 框柱指定方法&#xff0c;选择调试方法&#xff0c;gda会自动监听函数的返回值&#xff0c;例如 自定义frida脚本 gda会自动生成hook该函数的frida脚本

window.ai 开启你的内置AI之旅

❝ 成功是得你所想&#xff0c;幸福是享你所得 大家好&#xff0c;我是柒八九。一个专注于前端开发技术/Rust及AI应用知识分享的Coder ❝ 此篇文章所涉及到的技术有 AI( Gemini Nano) Chrome Ollama 因为&#xff0c;行文字数所限&#xff0c;有些概念可能会一带而过亦或者提供…

顶顶通呼叫中心中间件-外呼通道变量同步到坐席通道变量(mod_cti基于Freeswitch)

机器人伴随转人工或者排队转人工 把外呼通道同步到坐席通道变量 在拨号方案转人工动作cti_acd,或者转机器人动作cti_rotobt的前面&#xff0c;添加一个 export nolocal:变量名${变量名} 一、配置拨号方案 win-ccadmin配置方法 点击拨号方案 -> 点击进入排队 -> 根据图…

Java项目:基于SSM框架实现的中小企业人力资源管理系统【ssm+B/S架构+源码+数据库+开题报告+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的中小企业人力资源管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简…

jmeter-beanshell学习2-beanshell断言

继续写&#xff0c;之前写了获取变量&#xff0c;设置变量&#xff0c;今天先写个简单点的断言。 一般情况用响应断言&#xff0c;就挺好使&#xff0c;但是自动化还要生成报告&#xff0c;如果断言失败了&#xff0c;要保存结果&#xff0c;只能用beanshell处理&#xff0c;顺…

Ubuntu 24.04-自动安装-Nvidia驱动

教程 但在安全启动模式下可能会报错。 先在Nvidia官网找到GPU对应的驱动版&#xff0c; 1. 在软件与更新中选择合适的驱动 2. ubuntu自动安装驱动 sudo ubuntu-drivers autoinstall显示驱动 ubuntu-drivers devices3. 安装你想要的驱动 sudo apt install nvidia-driver-ve…