滑动窗口经典题目

目录

滑动窗口

什么是滑动窗口?

什么时候用滑动窗口?

怎么用滑动窗口?

209. 长度最小的子数组(滑动窗口的引入)

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

1004. 最大连续1的个数 III

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

904. 水果成篮

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

30. 串联所有单词的子串

76. 最小覆盖子串


滑动窗口

用209. 长度最小的子数组 - 力扣(LeetCode)这一题引入

什么是滑动窗口?

同向双指针,两个指针都不回退时

什么时候用滑动窗口?

当数组有单调性时(可能是数组本身有单调性,也可能是和)

怎么用滑动窗口?

1、初始化:初始化双指针

2、进窗口

3、判断

判断是不是要出窗口

❁ 更新结果(有些是在进窗口时,有些是在出窗口时)

209. 长度最小的子数组(滑动窗口的引入)

题目链接:. - 力扣(LeetCode)

题目要求满足sum >= target, 又因为数组内都是正整数,所以sum随着数组的遍历是递增的,有单调性的

有单调性时,我们可以想到:1、双指针 2、二分 3、滑动窗口

有了双指针就可以不用二分,因为双指针很多时候能降低时间复杂度

我们可以设置l指针为窗口的起点,r为窗口的终点

1、如果sum < target,r++

2、如果sum > target,l++

sum跟着上面变

我们会发现l和r是同向移动的,也就是“同向双指针”,滑动窗口的基本特点就是:1、单调性2、同向双指针

滑动窗口怎么用?

1、初始化l和r

2、进窗口

3、判断

     判断是否满足出窗口条件

以上环节注意更新结果(该题为sum),可能是在进窗口时改变,也可能是在出窗口时改变

正确性?

利用了单调性(该题为sum),规避了很多不必要的操作

(如sum > target时,我们不需要管r之后的数据了,因为题目要求求"长度最小的",r后面的数据一定满足sum > target,都是len是一直增大的,对于该题来说就是无用功)

时间复杂度:O(N)

虽然有两层循环,但是实际上时间复杂度是2*N,因为r最后结果是到末尾,为N,l最坏结果是也到末尾,也是N

因此时间复杂度不看循环层数,而是看实际操作

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {if (nums.size() == 0)return 0;int l = 0, r = 0;int sum = 0, len = INT_MAX;while (r < nums.size()){sum += nums[r];r++;while (sum >=/*注意有个=*/ target){len = min(len, r - l);sum -= nums[l];l++;}        }return len > nums.size() ? 0 : len;}
};

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

题目链接:3. 无重复字符的最长子串 - 力扣(LeetCode)

注意标记数组不能是大小为26,因为“s 由英文字母、数字、符号和空格组成”,所以最好开256

两个指针都是往后走,也就是同向指针 ----> 滑动窗口

class Solution
{
public:int lengthOfLongestSubstring(string s){int len = 0, l = 0, r = 0;int book[256] = { 0 };// 不只有字母while (r < s.size()){// 进窗口 book[s[r]]++;// 判断while (book[s[r]] > 1){// 出窗口book[s[l++]]--;}// 更新数据 len = max(len, r - l + 1);// 下一元素进窗口r++;}return len;}
};

1004. 最大连续1的个数 III

题目链接:. - 力扣(LeetCode)

解题思路:

滑动窗口解法

    1、初始化指针

       l = 0, r = 0

    2、进窗口

            1无视,0增加zero计数

    3、出窗口

            1无视,0减少计数

class Solution {
public:int longestOnes(vector<int>& nums, int k){if (k >= nums.size())return nums.size();int l = 0, r = 0;int len = 0;int zero = 0;// 记录当前范围0的个数while (r < nums.size()){// 进窗口if (!nums[r])zero++;// 判断while (zero > k)/**/{// 出窗口if (!nums[l++])zero--;}len = max(len, r - l + 1/*左闭右闭*/);r++;}return len;}
};

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

题目链接:. - 力扣(LeetCode)

解题思路:

       ❀ 正难则反,我们可以通过找“和为( 数组元素的和 - x )的最长连续子数组” ,来求得答案

     ❀ 上面那一步就是《双指针经典题目-CSDN博客》双指针经典题目中的《两数之和》的题目,其实滑动窗口本质上就是双指针,只不过它是同向移动的双指针

        ❀ 同时我们可以注意一下数据范围:1 <= nums[i] <= 10^4

            因此,我们可以知道数据元素都为正数,因此和具有单调性

class Solution {
public:// 正难则反// 找最长的子数组,使得其和为sum - xint minOperations(vector<int>& nums, int x) {int size = nums.size();if (min(nums[size - 1], nums[0]) > x)return -1;// 双指针,都指向数组开头,然后同向移动,找最大长度int l = 0, r = 0;int totalsum = 0;// 整个数组的和for (auto e : nums)totalsum += e;totalsum -= x;// 整个数组的和 - x// 因为数据元素都为正数if (totalsum == 0)return nums.size();else if (totalsum < 0)return -1;int sum = 0;int len = 0;for (r = 0; r < nums.size(); r++){sum += nums[r];while (l < r && sum > totalsum){sum -= nums[l];l++;}if (sum == totalsum){len = max(len, r - l + 1);}}if (!len)return -1;return nums.size() - len;}
};

904. 水果成篮

904. 水果成篮 - 力扣(LeetCode)

class Solution {
public:int totalFruit(vector<int>& fruits){int hash[100001] = { 0 };int l = 0, r = 0;int ret = 0;int size = 0;for (r = 0; r < fruits.size(); r++){if (hash[fruits[r]] == 0)size++;// 进窗口hash[fruits[r]]++;// 出窗口while (size > 2){hash[fruits[l]]--;if (hash[fruits[l]] == 0)size--;l++;}// 更新结果ret = max(ret, r - l + 1);}cout << ret << endl;return ret;}
};

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

题目链接:438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

如何知道两个字符串是否为异位词?
1、可以给两个字符串排序(时间复杂度高)
2、用两个哈希表分别记录两个子串的各个字母个数

该题解法:滑动窗口 + 哈希表
该题的滑动窗口:右边进入一个数值,左边出一个数值,维持窗口大小不变
用一个count记录有效字符的个数
    1、进窗口
        如果是有效字符,count++
    2、出窗口
        更新结果:如果count == p.size(),ans.push_back(l);
            出窗口:如果是有效字符,count--

class Solution
{
public:vector<int> findAnagrams(string s, string p) {int hash1[26] = { 0 };int hash2[26] = { 0 };        for (auto e : p)hash1[e - 'a']++;int l = 0, r = 0;vector<int> ans;int count = 0;while (r < s.size()){// 进窗口hash2[s[r] - 'a']++;// 说明是有效字符if (hash2[s[r] - 'a'] <= hash1[s[r] - 'a'])count++;if (r - l + 1 == p.size()){if (count == p.size()){ans.push_back(l);hash2[s[l] - 'a']--;count--;// 移除的一定是有效字符}else// count < p.size(){hash2[s[l] - 'a']--;// 删除的是有效字符if (hash2[s[l] - 'a'] < hash1[s[l] - 'a'])count--;}l++;}r++;}return ans;}
};

30. 串联所有单词的子串

题目链接:30. 串联所有单词的子串 - 力扣(LeetCode)

解题思路:

        将题目想为“在s中找words的异位词” 

class Solution
{
public:vector<int> findSubstring(string s, vector<string>& words){// 滑动窗口的次数int size = words[0].size();// 检验字符串的长度int len = words.size() * words[0].size();unordered_map<string, int> mp1;unordered_map<string, int> mp2;vector<int> ans;for (auto e : words)mp1[e]++;// 看是否是串联子串int l = 0, r = words[0].size();int prel = 0;// 看是否构成一个单词int midl = 0, midr = words[0].size();while (size--){// 有效字符串的个数int count = 0;mp2.clear();while (r <=/*注意有一个等于,因为构造字符串是左闭右开,在构造最后一个单词的时候,r要等于s.end()*/ s.size()){// 进窗口 string temp(s.begin() + midl, s.begin() + midr);// string temp = s.substr(l, words[0].size());mp2[temp]++;if (mp2[temp] <= mp1[temp])count++;if (r - l == len){string temp(s.begin() + l, s.begin() + l + words[0].size());mp2[temp]--;if (count == words.size()){ans.push_back(l);count--;}else{if (mp2[temp] < mp1[temp])count--;}l += words[0].size();}r += words[0].size();midr += words[0].size();midl += words[0].size();}l = ++prel;midl = l;r = l + words[0].size();midr = midl + words[0].size();}return ans;}
};

76. 最小覆盖子串

题目链接:. - 力扣(LeetCode)

1、暴力解法:两层循环 + 哈希表
2、优化解法:滑动窗口 + 哈希表

kind:t中字符的种类
count:s中字符的种类(注意!不是个数)

进窗口
    如果是t中的字符,并且++hash1[r] == hash2[r],count++
判断
        如果--hash2[l] < hash1[l],count--
    出窗口
        如果出的数据不是t中的数据,r不变
        如果出的数据是t中的数据,r++

更新结果

class Solution {
public:string minWindow(string s, string t){if (s.size() < t.size())return "";int l = 0, r = 0;int hash1[256] = { 0 };int hash2[256] = { 0 };int kind = 0;for (auto e : t){if (hash1[e]++== 0)kind++;}int count = 0;int len = INT_MAX;int lenl = 0;for (r = 0; r < s.size(); r++){hash2[s[r]]++;if (hash2[s[r]] == hash1[s[r]])count++;while (count == kind){if ((r - l + 1) < len){len = r - l + 1;lenl = l;}if (hash2[s[l]]-- == hash1[s[l]])count--;l++;}}if (len == INT_MAX)return "";return s.substr(lenl, len);}
};

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

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

相关文章

Fyne ( go跨平台GUI )中文文档-容器和布局 (四)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章&#xff1a; Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI…

【重学 MySQL】三十七、聚合函数

【重学 MySQL】三十七、聚合函数 基本概念5大常用的聚合函数COUNT()SUM()AVG()MAX()MIN() 使用场景注意事项示例查询 聚合函数&#xff08;Aggregate Functions&#xff09;在数据库查询中扮演着至关重要的角色&#xff0c;特别是在处理大量数据时。它们能够对一组值执行计算&a…

37. Vector3与模型位置、缩放属性

本文章给通过组对象Group (opens new window)给大家讲解一下threejs层级模型或树结构的概念。 Group层级模型(树结构)案例 下面代码创建了两个网格模型mesh1、mesh2&#xff0c;通过THREE.Group类创建一个组对象group,然后通过add方法把网格模型mesh1、mesh2作为设置为组对象g…

Vuex的使用看这一篇就够了

Vuex概述 Vuex 是一个专为 Vue.js 应用程序开发的状态管理库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以一种可预测的方式来保证状态以一种可预测的方式发生变化。 state状态 把公用的数据放到store里的state就行了&#xff0c;上面是vue2的代码&#xff0c;下…

[大语言模型] LINFUSION:1个GPU,1分钟,16K图像

1. 文章 2409.02097 (arxiv.org)https://arxiv.org/pdf/2409.02097 LINFUSION: 1 GPU, 1 MINUTE, 16K IMAGE 摘要 本文介绍了一种新型的扩散模型LINFUSION&#xff0c;它能够在保持高分辨率图像生成性能的同时显著降低时间和内存复杂度。该模型采用了基于Transformer的UNet进…

【前端】ES6:Class语法和Class继承

文章目录 1 Class语法1.1 类的写法1.2 getter与setter1.3 静态属性和静态方法 2 Class继承 1 Class语法 1.1 类的写法 class Person {constructor(name,age){this.name name;this.age age;}say(){console.log(this.name,this.age)} } let obj new Person("kerwin&quo…

python--基础语法(2)

1.顺序语句 默认情况下&#xff0c;Python的代码执行顺序是按照从上到下的顺序&#xff0c;依次执行的。 2.条件语句 条件语句能够表达“如果 ...否则 ...”这样的语义这构成了计算机中基础的逻辑判定条件语&#xff0c; 也叫做 分支语句。表示了接下来的逻辑可能有几种走向…

SysML图例-10cm最小航天器AC-10

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>> SysML图中词汇 AC10 AeroCube-10&#xff0c;大小仅为10 10 15 cm的卫星&#xff0c;更多信息参见下文&#xff1a; AeroCube-10成为迄今为止完成在轨接近操作的最小航天…

yolov8模型在手部关键点检测识别中的应用【代码+数据集+python环境+GUI系统】

yolov8模型在手部关键点检测识别中的应用【代码数据集python环境GUI系统】 背景意义 在手势识别、虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;等领域&#xff0c;手部关键点检测为用户提供了更加自然、直观的交互方式。通过检测手部关键点&#…

移动登录页:让用户开启一段美好的旅程吧。

Hi,大家好&#xff0c;我是大千UI工场&#xff0c;移动登录页千千万&#xff0c;这里最好看&#xff0c;本期分享一批移动端的登录页面&#xff0c;供大家欣赏。 本次分享的是毛玻璃/3D风格的登录页。

Linux文件IO(七)-复制文件描述符

在 Linux 系统中&#xff0c;open 返回得到的文件描述符 fd 可以进行复制&#xff0c;复制成功之后可以得到一个新的文件描述符&#xff0c;使用新的文件描述符和旧的文件描述符都可以对文件进行 IO 操作&#xff0c;复制得到的文件描述符和旧的文件描述符拥有相同的权限&#…

【文化课学习笔记】【化学】选必三:合成高分子生物大分子

【化学】选必三&#xff1a;合成高分子&生物大分子 如果你是从 B 站一化儿笔记区来的&#xff0c;请先阅读我在第一篇有机化学笔记中的「读前须知」(点开头的黑色小三角展开)&#xff1a;链接 加聚反应 基本概念 聚合反应 由小分子化合物合成高分子化合物的反应叫聚合反应。…

学习 git 命令行的简单操作, 能够将代码上传到 Gitee 上

首先登录自己的gitee并创建好仓库 将仓库与Linux终端做链接 比如说我这里已经创建好了一个我的Linux学习仓库 点开克隆/下载&#xff1a; 在你的终端中粘贴上图中1中的指令 此时他会让你输入你的用户名和密码&#xff0c;用户名就是上图中3中Username for ....中后面你的一个…

秒变 Vim 高手:必学的编辑技巧与隐藏功能大揭秘

文章目录 前言一、vi与vim二、Vim的三种模式1. 普通模式2. 插入模式3. 命令模式 三、Vim中的查找与替换1. 查找2. 替换 四、给Vim设置行号1. 临时显示行号2. 永久显示行号 总结 前言 在Linux系统中&#xff0c;文本编辑器是开发者和系统管理员日常工作中的重要工具之一。其中&…

手机号归属地查询-运营商归属地查询-手机号归属地信息-运营商手机号归属地查询接口-手机号归属地

手机号归属地查询接口是一种网络服务接口&#xff0c;它允许开发者通过编程方式查询手机号码的注册地信息。这种接口通常由第三方服务提供商提供&#xff0c;并可通过HTTP请求进行调用。以下是一些关于手机号归属地查询接口的相关信息&#xff1a; 1. 接口功能 归属地查询&am…

HTB-GreenHorn 靶机笔记

GreenHorn 靶机笔记 概述 GreenHorn 是 HTB 上的一个 linux easy 难度的靶机&#xff0c;主要是通过信息搜集和代码审计找到对我们有用的信息。其中还包含了对pdf文件的修复技术 靶机地址&#xff1a;https://app.hackthebox.com/machines/GreenHorn 一丶 nmap 扫描 1&…

https加密原理

以为http的数据都是以明文传送&#xff0c;会有很大的安全问题&#xff0c;所以出现的https协议。https就是在http协议的基础上增加了一个安全层&#xff0c;可以对数据进行加密和解密(例如SSL、TLS等)。 https加密解密的原理&#xff1a;证书非对称加密对称加密 在讲解原理前…

用友网络交付总监刘伟伟受邀为第四届中国项目经理大会演讲嘉宾

全国项目经理专业人士年度盛会 用友网络科技股份有限公司区域交付总监刘伟伟先生受邀为PMO评论主办的全国项目经理专业人士年度盛会——2024第四届中国项目经理大会演讲嘉宾&#xff0c;演讲议题为“如何有效提升项目经理领导力”。大会将于10月26-27日在北京举办&#xff0c;主…

蓝桥杯模块一:LED指示灯的基本控制

模块训练一:LED指示灯的基本控制 模块1到模块13都是通过I\O模式进行设计 一、电路图 二、电路分析 1.74HC573锁存器介绍 OE端接地&#xff0c;上电即工作&#xff0c;控制LE端&#xff0c;当LE端接高电平时&#xff0c;锁存器开始工作&#xff0c;接通D和Q 2.电路工作原理分析…

文件操作和InputStream,OutputStream的用法

“他越拧巴&#xff0c;我越喜欢&#xff01;” 文件&#xff1a; 此处谈到的文件&#xff0c;本身有很多的含义。 狭义上的文件&#xff0c;特指 硬盘上的文件&#xff08;以及保存文件的目录&#xff09;。 广义上的文件&#xff0c;计算机上的很多硬件设备&#xff0c;软…