【算法一周目】滑动窗口(2)
目录
水果成篮
解题思路
代码实现
找到字符串中所有字母异位词
解题思路
代码实现
串联所有单词的子串
解题思路
代码实现
最小覆盖子串
解题思路
代码实现
水果成篮
题目链接:904. 水果成篮
题目描述:
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果种类。你想要尽可能多地收集水果,但是有一些规则:
- 你有两个篮子,每个篮子只能装一种类型的水果,篮子的容量无限制。
- 你可以选择任意一棵树开始采摘,但必须从这棵树开始依次向右采摘每棵树上的水果。
- 一旦遇到某棵树上的水果不符合篮子中的水果种类,你必须停止采摘。
返回你能采摘的最多的水果数量。

解题思路
解法:滑动窗口+哈希
根据题目要求,所求问题其实就是找一段最多只含两个不同元素的最长子区间,我们使用滑动窗口+哈希解决。
有一点值得注意,fruits[i] 是第 i 棵树上的水果种类,不是种类数。
具体过程如下:
- 1.初始化哈希表 hash,左右指针 left 和 right,记录结果的变量 ret。
- 2.right 向右遍历数组,将 right 位置的水果加入哈希表,统计频次。
- 如果哈希表的大小超过2,让left++并同时更新哈希表,直至哈希表的大小不超过2。
- 3.更新结果 ret。
- 4重复上述过程,直到 right 遍历完数组。
代码实现
1.使用unordered_map作为hash表
class Solution {
public:int totalFruit(vector<int>& fruits) {// 统计滑动窗口内水果的种类和数量unordered_map<int, int> hash;int n = fruits.size(), ret = 0;for(int left = 0, right = 0; right < n; right++){//进窗口,将水果加入hash表hash[fruits[right]]++;//若水果种类超过2,收缩窗口直到种类不超过2while(hash.size() > 2){hash[fruits[left]]--;if(hash[fruits[left]] == 0) hash.erase(fruits[left]);left++;}//更新结果ret = max(ret, right - left + 1);}return ret;}
};
2.使用数组模拟hash表
题目其实有提到 fruits[i] 的范围,所以我们不必真的使用unordered_map作为hash表,使用数组模拟即可,这样虽然会浪费空间,但是提高了效率。
class Solution {
public:int totalFruit(vector<int>& fruits) {int hash[100000] = { 0 };//cnt用于统计hash表的水果的种类个数int n = fruits.size(), ret = 0, cnt = 0;for(int left = 0, right = 0; right < n; right++){hash[fruits[right]]++;if(hash[fruits[right]] == 1) cnt++;while(cnt > 2){hash[fruits[left]]--;if(hash[fruits[left++]] == 0) cnt--;}ret = max(ret, right - left + 1);}return ret;}
};
时间复杂度:O(n)
空间复杂度:O(n)
找到字符串中所有字母异位词
题目链接:438. 找到字符串中所有字母异位词
题目描述:
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。顺序可以不考虑。
异位词是指由相同字母重排列形成的字符串(包括相同的字符串)。

解题思路
解法:滑动窗口 + 哈希
因为字符串 p 的异位词的长度一定于字符串 p 的长度相等,所以我们可以在字符串 s 中使用与字符串 p 等长度的滑动窗口来求解。
我们可以使用两个大小为26的数组来模拟哈希表,用于统计窗口内的字母频次和字符串s的字母频次,当比较得到两个哈希表相等时,说明滑动窗口中每种字母的数量与字符 p 每种字母的数量相同,窗口内的字符是字符 p 的一个异位词,此时记录窗口起始索引。
具体过程如下:
- 1.初始化 left 和 right 指针来维护滑动窗口,两个大小为26的数组 hash1 和 hash2 来模拟哈希表,记录字符串 p 的字母频次和窗口字母频次。
- 2.right 向右遍历数组
- right 位置的字母入窗口,将其加入哈希表。
- 当滑动窗口长度大于字符串 p 的长度时,left++,将窗口左侧字母移除同时更新其在哈希表的频次。
- 3.更新结果,当 hash1 与 hash2 相等时,记录窗口起始索引。
注意:判断两个 hash 表是否相等的时间复杂度较高,效率较低。故我们要优化更新结果的判断条件(两个哈希表相等),我们可以来使用一个变量 cnt 记录窗口内的字母相较于字符串 p 的有效字符的数量,并在入窗口和窗口时维护 cnt,这样更新结果时,只需判断 cnt 是否等于字符串 p 的长度就可以知道窗口字符是否是字符串 p 的异位词。
解释下有效字符的数量,其实就是让窗口的组成字母尽可能接近字符 p ,当有效字符的数量等于字符 p 的长度,就说明了窗口的字母频次与字符 p 的字母频次相等,这也是比较两个统计字母频次的哈希表相等的本质,cnt 间接完成了这个任务。
代码实现
class Solution {
public:vector<int> findAnagrams(string s, string p) {vector<int> ret;int n = s.size(), m = p.size();//统计p字符串中每个字母出现的个数int hash1[26] = { 0 };for(auto ch : p) hash1[ch - 'a']++;//统计窗口中每个字母出现的个数int hash2[26] = { 0 };//统计窗口中有效字符的数量int cnt = 0;for(int left = 0, right = 0; right < n; right++){//进窗口 + 维护cntchar in = s[right];hash2[in - 'a']++;if(hash2[in - 'a'] <= hash1[in - 'a']) cnt++;//窗口长度大于字符串p的长度,窗口左端字母出窗口,//并更新cnt和哈希表if(right - left + 1 > m){char out = s[left++];//出窗口 + 维护cntif(hash2[out - 'a'] <= hash1[out - 'a']) cnt--;hash2[out - 'a']--;}//更新结果if(cnt == m) ret.push_back(left);}return ret;}
};
时间复杂度:O(n)
空间复杂度:O(1)
串联所有单词的子串
题目链接:30. 串联所有单词的子串
题目描述:
给定一个字符串 s 和一个字符串数组 words,words 中所有字符串的长度相同。s 中的 串联子串 是指包含 words 中所有字符串以任意顺序排列连接起来的子串。
例如,如果 words = ["ab","cd","ef"],那么 "abcdef", "abefcd", "cdabef", "cdefab", "efabcd" 和 "efcdab" 都是串联子串,而 "acdbef" 不是串联子串,因为它不是 words 排列的连接。
返回所有串联子串在 s 中的开始索引,顺序可以不考虑。

解题思路
解法:滑动窗口 + 哈希表
这道题就是找到字符串中所有字母异位词的升级版,从原来处理单个字符变成了处理单个单词,我们只需要将 words 的单词看成单个字母就行了,然后用滑动窗口 + 哈希表解决。

具体过程:
1.用哈希表 hash1 记录 words 中每个单词的频次。
2.遍历字符串 s ,并用哈希表 hash2 来维护滑动窗口内的单词频次,注意每次增加窗口的大小为单词的长度。
3.当窗口大小大于所有单词的总长度时,出窗口和更新 hash2 。
4.当 hash1 和 hash2 两个哈希表相等时,更新结果。
判断两个哈希表是否相等消耗较大,用 count 来优化,count 统计滑动窗口内有效单词的个数。当 count 与 words 的单词个数相等时,说明找到了符合条件的一个窗口。
代码实现
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 len = words[0].size(), m = words.size(), n = s.size();//执行len次滑动窗口for(int i = 0; i < len; ++i){unordered_map<string, int> hash2;for(int left = i, right = i, count = 0; right <= n - len; right += len){//进窗口+维护countstring in(s.begin() + right, s.begin() + right + len);hash2[in]++;if(hash1.count(in) && hash2[in] <= hash1[in]) count++;//判断+出窗口+维护countif(right - left + 1 > m * len){string out(s.begin() + left, s.begin() + left + len);if(hash1.count(out) && hash2[out] <= hash1[out]) count--;hash2[out]--;left += len;}//更新结果if(count == m)ret.push_back(left);}}return ret;}
};
1.执行 len 次滑动窗口(len 是单词长度):由 s 字符串的长度不一定是单词长度的整数倍,需要执行 len 滑动窗口来保证答案的完整性。
2.注意 right 的范围,right 最后一次执行循环的位置应该是在 n - len 处。
时间复杂度:O( n * len),其中 n 是字符串 s 的长度,需要 len 次滑动窗口,每次遍历一次 s。
空间复杂度:O(m * len),m 是单词个数,每次滑动窗口都需要用一个哈希表来存储单词频次。
最小覆盖子串
题目链接:76. 最小覆盖子串
题目描述:
给你一个字符串 s 和一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在这样的子串,则返回空字符串 ""。
注意:
- 对于
t中重复的字符,最小子串中该字符数量必须不少于t中的字符数量。 - 如果存在这样的子串,答案是唯一的。

解题思路
解法:滑动窗口+哈希
根据题目,我们直接根据暴力解法来优化,就得到滑动窗口+哈希的解题方法。
具体过程如下:
1.利哈希表 hash1 来统计字符串 t 中每个字符出现的频次。
2.使用滑动窗口遍历字符串 s ,并用哈希表 hash2 来统计窗口中字符频次。
3.当窗口的字符频次满足要求时,更新结果,然后收缩窗口,直到窗口字符频次不满足要求。
注意:这里判断窗口的字符频次满足要求不是判断两个哈希表是否相等,而是 hash1 的字符频次要完整的出现在 hash2 中,hash1 中可以出现除字符串 t 中的字符以外的字符频次。也就是说,窗口内只要完整出现字符串 t 的所有字符即可(字符种类及其对应的频次)。
我们这里还是利用 count 来完成判断,这里的 count 统计的时有效字符的种类,只有 t 中的单个字符在窗口内出现的频次与在 t 中完全一样,count 才自增1,同理,频次不相等时就自减 1,当 count 与 t 中字符种类数相同时,说明找到一个符合条件的覆盖字串,更新结果。
代码实现
class Solution {
public:string minWindow(string s, string t) {string ret;//hash1统计t字符频次和计算hash1的大小,hash1size统计t的字符种类int hash1[128] = { 0 }, hash1size = 0;for(auto e : t) if(hash1[e]++ == 0) hash1size++;//hash2统计窗口字符频次int hash2[128] = { 0 };int len = INT_MAX, start = 0;//count统计有效字符的种类for(int left = 0, right = 0, count = 0; right < s.size(); right++){//进窗口 + 维护countchar in = s[right];if(++hash2[in] == hash1[in]) count++;//判断while(count == hash1size){//更新结果if(right - left + 1 < len){len = right - left + 1;start = left;}//出窗口+维护countchar out = s[left++];if(hash2[out]-- == hash1[out]) count--;}}ret = len == INT_MAX ? "" : s.substr(start, len);return ret;}
};
时间复杂度:O(n)
空间复杂度:O(1)
拜拜,下期再见😏
摸鱼ing😴✨🎞

相关文章:
【算法一周目】滑动窗口(2)
目录 水果成篮 解题思路 代码实现 找到字符串中所有字母异位词 解题思路 代码实现 串联所有单词的子串 解题思路 代码实现 最小覆盖子串 解题思路 代码实现 水果成篮 题目链接:904. 水果成篮 题目描述: 你正在探访一家农场,农场…...
Zustand:一个轻量级的React状态管理库
文章目录 前言一、安装Zustand二、使用Zustand三、实际案例结语 前言 在现代Web开发中,状态管理是一个常见的需求,特别是在构建大型或复杂的单页面应用程序(SPA)时。React等框架虽然提供了基本的状态管理功能,但对于复…...
C++练级计划->《单例模式》懒汉和饿汉
目录 单例模式是什么? 单例模式的应用: 饿汉单例模式: 1.实现: 2.理解: 懒汉单例模式: 1.实现: 2.理解: 懒汉和饿汉的优缺点 饿汉模式的优点: 饿汉模式的缺点&a…...
SQL for XML
关系数据模型与SQL SQL for XML 模式名功能RAW返回的行作为元素,列值作为元素的属性AUTO返回表名对应节点名称的元素,每列的属性作为元素的属性输出输出,可形成简单嵌套结构EXPLICIT通过SELECT语法定义输出XML结构PATH列名或列别名作为XPAT…...
如何使用GCC手动编译stm32程序
如何不使用任何IDE(集成开发环境)编译stm32程序? 集成开发环境将编辑器、编译器、链接器、调试器等开发工具集成在一个统一的软件中,使得开发人员可以更加简单、高效地完成软件开发过程。如果我们不使用KEIL,IAR等集成开发环境,…...
在线绘制Nature Communication同款双色、四色火山图,突出感兴趣的基因
导读:火山图通常使用三种颜色分别表示显著上调,显著下调和不显著。通过为特定的数据点添加另一种颜色,可以创建双色或四色火山图,从而更直观地突出感兴趣的数据点。 《Nature Communication》文章“Molecular and functional land…...
C语言:C语言实现对MySQL数据库表增删改查功能
基础DOME可以用于学习借鉴; 具体代码 #include <stdio.h> #include <mysql.h> // mysql 文件,如果配置ok就可以直接包含这个文件//宏定义 连接MySQL必要参数 #define SERVER "localhost" //或 127.0.0.1 #define USER "roo…...
C++ 二叉搜索树(Binary Search Tree, BST)深度解析与全面指南:从基础概念到高级应用、算法优化及实战案例
🌟个人主页:落叶 🌟当前专栏: C专栏 目录 ⼆叉搜索树的概念 ⼆叉搜索树的性能分析 ⼆叉搜索树的插⼊ ⼆叉搜索树的查找 二叉搜索树中序遍历 ⼆叉搜索树的删除 cur的左节点为空的情况 cur的右节点为空的情况 左,右节点都不为…...
刷题日常(移动零,盛最多水的容器,三数之和,无重复字符的最长子串)
移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 俩种情况: 1.当nums[i]为0的时候 直接i 2.当nums[i]不为0的时候 此时 …...
深入了解决策树---机器学习中的经典算法
引言 决策树(Decision Tree)是一种重要的机器学习模型,以直观的分层决策方式和简单高效的特点成为分类和回归任务中广泛应用的工具。作为解释性和透明性强的算法,决策树不仅适用于小规模数据,也可作为复杂模型的基石&…...
Elasticsearch对于大数据量(上亿量级)的聚合如何实现?
大家好,我是锋哥。今天分享关于【Elasticsearch对于大数据量(上亿量级)的聚合如何实现?】面试题。希望对大家有帮助; Elasticsearch对于大数据量(上亿量级)的聚合如何实现? 1000道 …...
深度学习模型:循环神经网络(RNN)
一、引言 在深度学习的浩瀚海洋里,循环神经网络(RNN)宛如一颗独特的明珠,专门用于剖析序列数据,如文本、语音、时间序列等。无论是预测股票走势,还是理解自然语言,RNN 都发挥着举足轻重的作用。…...
前端---HTML(一)
HTML_网络的三大基石和html普通文本标签 1.我们要访问网络,需不需要知道,网络上的东西在哪? 为什么我们写,www.baidu.com就能找到百度了呢? 我一拼ping www.baidu.com 就拼到了ip地址: [119.75.218.70]…...
SQL 复杂查询
目录 复杂查询 一、目的和要求 二、实验内容 (1)查询出所有水果产品的类别及详情。 查询出编号为“00000001”的消费者用户的姓名及其所下订单。(分别采用子查询和连接方式实现) 查询出每个订单的消费者姓名及联系方式。 在…...
银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法
银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法 1、支持环境2、详细操作说明步骤1:用root账户登录电脑步骤2:导航到kylin-wm-chooser目录步骤3:编辑default.conf文件步骤4:重启电脑 3、结语 Ὁ…...
抓包之使用chrome的network面板
写在前面 本文看下工作中非常非常常用的chrome的network面板功能。 官方介绍:地址。 1:前置 1.1:打开 右键-》检查,或者F12。 1.2:组成部分 2:控制器常用功能 详细如下图: 接着我们挑选其…...
避坑ffmpeg直接获取视频fps不准确
最近在做视频相关的任务,调试代码发现一个非常坑的点,就是直接用ffmpeg获取fps是有很大误差的,如下: # GPT4o generated import ffmpegprobe ffmpeg.probe(video_path, v"error", select_streams"v:0", sho…...
大数据新视界 -- 大数据大厂之 Hive 函数库:丰富函数助力数据处理(上)(11/ 30)
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...
深入解析 Django 中数据删除的最佳实践:以动态管理镜像版本为例
文章目录 引言场景与模型设计场景描述 删除操作详解1. 删除单个 Tag2. 批量删除 Tags3. 删除前确认4. 日志记录 高阶优化与问题分析1. 外键约束与误删保护2. 并发删除的冲突处理3. 使用软删除 结合 Django Admin 的实现总结与实践思考 引言 在现代应用开发中,服务和…...
【java】sdkman-java多环境切换工具
#java #env #sdk #lcshand 首先我们来复习一下,可参考我原来的文章: python多个版本的切换可用pyenv nodejs多个版本的切换可用nvm 同样,java多个版本的切换可用sdkman和jenv,我偏重于使用sdkman,因为有时候我也需要…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
