滑动窗口篇——如行云流水般的高效解法与智能之道(3)

前言:

上篇我们介绍了滑动窗口的进阶练习,本篇难度继续升级,同样结合具体题目,帮助大家进一步掌握和运用滑动窗口。 

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

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

题目分析:

题目要求返回所有异位词起始索引,我们首先来了解什么是异位词和起始索引

异位词:

1. 观察其示例可知,两个字符串的长度和所含字母相同

2. 字母的排列顺序不同

起始索引:该异位词的首字母在原先的字符串中的下标。

思路讲解:

首先可以考虑使用哈希表进行字符串的匹配问题:

字符匹配:

1. 首先用hash2对字符串p中的字符进行一一存储映射

2. 对s中将要匹配的字符串同样进行哈希映射处理

3. 如果两个哈希表完全相同,则该哈希表存储的字符串即为一个异位词 

不难发现,在向后遍历进行存储时,为一个连续的区间,因此同样可尝试使用滑动窗口解决。

滑动窗口:

1. 定义都为0的left和right,right向后遍历的同时进行哈希映射存储,即为进窗口操作。 

2. 当窗口长度大于字符串p的长度时,此处绝对不可能为异位词,因此需要left向后遍历的同时更改哈希映射存储,即为出窗口操作

3. 当窗口长度与p的长度相等时,即可进行上面提到的字符匹配操作,如果成功匹配,则在vector数组ret中尾插中left的索引,反之则继续进行滑动窗口操作。

算法优化: 

问题:每次字符匹配时,都需要进行26次的判断操作,虽然次数不算多,但在字符串长度较大时,仍会造成较大的时间损耗,那么我们该如何进行优化呢?

解答:大量时间损耗产生的原因是因为冗余的字符匹配,我们可以通过字符计数的方式进行匹配。

1. 异位词的基本要求就是长度相等,另外还需要出现的所有字母次数相同。

2. 我们可以把字符串p的长度记录为m,窗口内有效字母数记为count。

3. 入窗口时的哈希映射记录为in,当入窗口操作时,如果hash1[in]<=hash2[in],说明进入了一个有效字母,count++。

4. 出窗口时的哈希映射记录为out,当出窗口操作时,如果hash2[out]<=hash2[out],说明失去了一个有效字母,count--。

5. 当count与m相等时,代表两个字符串的有效字母也相等,此时一定为异位词,直接在vector数组ret中尾插left的索引即可。

代码实现:

class Solution {
public:vector<int> findAnagrams(string s, string p) {int hash2[26]={0};//模拟哈希匹配字符串pint hash1[26]={0};//模拟哈希表记录窗口内的元素情况int m=p.size();//记录p的长度vector<int> ret;for(auto e:p){hash2[e-'a']++;}//存储p中字母出现的次数for(int left=0,right=0,count=0;right<s.size();right++){char in=s[right];//进窗口的元素if(++hash1[in-'a']<=hash2[in-'a']){count++;}//进窗口同时维护countif(right-left+1>m){char out=s[left++];if(hash1[out-'a']--<=hash2[out-'a']){count--;}}//出窗口的同时维护countif(count==m){ret.push_back(left);}}return ret;}
};

 注意:

该代码在进行进出窗口操作时,进行了小优化,即在if操作时,既进行了哈希表存储映射的更新,又维护了count。

二. 串联所有单词的子串

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

题目分析:

1. 题目中,words是一个字符数组,且每个元素的长度相同 

2. 要求返回字符串s内的所有串联子串的起始索引。

起始索引在上题中我们已经谈到,因此我们先来了解一下什么是串联子串

1. 串联子串与words内所有元素相同,且长度即为字符数组的长度。

2. 串联子串中字母的排列顺序与字符数组内元素的排列顺序不同。

不难发现,其实串联子串就是进阶版的异位词。 

算法讲解: 

思路与上题相同,我们只需要把words内的每个元素看作是上题的一个字母即可。

1. 首先利用哈希表存储words内的元素,len表示单个单词的长度,m表示words内的元素个数

2.  与上题中right每次移动一个字母不同,这次right每次需要移动len个长度,并且循环终止条件为right+len<=s.size(),如果不取等于,那么最后一组数据会无法遍历完全。

3. 同时,外层需要嵌套一层执行次数为len次的for循环,表示以第一个单词的各个位置作为进出窗口的起始位置进行遍历。

4. 进出窗口与代码优化维护count操作与上类似。

代码实现:

class Solution {
public:vector<int> findSubstring(string s, vector<string>& words) {unordered_map<string,int> hash2;//利用哈希表映射wordsvector<int> ret;for(auto e:words){hash2[e]++;}int len=words[0].size(),m=words.size();//分别记录单个单词的长度和单词个数for(int i=0;i<len;i++)//执行len次{unordered_map<string,int> hash1;//for(int left=i,right=i,count=0;right+len<=s.size();right+=len){string in=s.substr(right,len);//剪切出需要进窗口的子串hash1[in]++;if(hash1.count(in)&&hash1[in]<=hash2[in]){count++;}//进窗口同时维护countif(right-left+1>len*m){string out=s.substr(left,len);//剪切出需要出窗口的子串if(hash1.count(out)&&hash1[out]<=hash2[out]){count--;}hash1[out]--;left+=len;}//出窗口同时维护countif(count==m){ret.push_back(left);}}}return ret;}
};

 三. 最小覆盖子串

题目链接:76. 最小覆盖子串 - 力扣(LeetCode)

题目分析:

题目给出两个字符串s和t,要求求出s内的最小覆盖子串,若不存在,则返回空。

我们首先来了解一下覆盖子串的定义:

1. 由示例不难看出,覆盖字串至少需要涵盖t内的所有字母

2. 覆盖子串内的字母顺序不做要求

3. 易得覆盖字串即为第一题异位词的扩大版

注意:字符串内的字母可能为大写也可能为小写!!! 

思路讲解:

研究对象是连续的区间,因此可以尝试使⽤滑动窗⼝的思想来解决。
如何判断当前窗⼝内的所有字符是符合要求的呢?

我们可以使⽤两个哈希表,其中⼀个将⽬标串的信息统计起来,另⼀个哈希表动态的维护窗口内字符串的信息。
当动态哈希表中包含⽬标串中所有的字符,并且对应的个数都不⼩于⽬标串的哈希表中各个字符的个数,那么当前的窗⼝就是⼀种可⾏的⽅案。

具体过程如下:

定义两个全局的哈希表:

1 号哈希表 hash1 ⽤来记录⼦串的信息, 2 号哈希表 hash2
⽤来记录⽬标串 t 的信息;
b. 实现⼀个接⼝函数,判断当前窗⼝是否满⾜要求:
i. 遍历两个哈希表中对应位置的元素:
• 如果 t 中某个字符的数量⼤于窗⼝中字符的数量,也就是 2 号哈希表某个位置⼤于
1 号哈希表。说明不匹配,返回 false ;
• 如果全都匹配,返回 true 。
主函数中:
a. 先将 t 的信息放⼊ 2 号哈希表中;
b. 初始化⼀些变量:左右指针: left = 0,right = 0 ;⽬标⼦串的⻓度: len = 
INT_MAX ;⽬标⼦串的起始位置: retleft ;(通过⽬标⼦串的起始位置和⻓度,我们就
能找到结果)
c. 当 right ⼩于字符串 s 的⻓度时,⼀直下列循环:
i. 将当前遍历到的元素扔进 1 号哈希表中;
ii. 检测当前窗⼝是否满⾜条件:
• 如果满⾜条件:
◦ 判断当前窗⼝是否变⼩。如果变⼩:更新⻓度 len ,以及字符串的起始位置
retleft ;
◦ 判断完毕后,将左侧元素滑出窗⼝,顺便更新 1 号哈希表;

◦ 重复上⾯两个过程,直到窗⼝不满⾜条件;
iii. right++ ,遍历下⼀个元素;
d. 判断 len 的⻓度是否等于 INT_MAX :
i. 如果相等,说明没有匹配,返回空串;
ii. 如果不相等,说明匹配, 返回 s 中从 retleft 位置往后 len ⻓度的字符串。

代码实现:

class Solution {
public:string minWindow(string s, string t) {int hash1[128] = {0}; // 统计字符串 t 中每⼀个字符的频次int kinds = 0;        // 统计有效字符有多少种for (auto ch : t)if (hash1[ch]++ == 0)kinds++;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];if (++hash2[in] == hash1[in])count++;           // 进窗⼝ + 维护 countwhile (count == kinds) // 判断条件{if (right - left + 1 < minlen) // 更新结果{minlen = right - left + 1;begin = left;}char out = s[left++];if (hash2[out]-- == hash1[out])count--; // 出窗⼝ + 维护 count}}if (begin == -1)return "";elsereturn s.substr(begin, minlen);}
};

小结:本文介绍了滑动窗口的进阶用法,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!! 

 

 

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

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

相关文章

uniapp首页样式,实现菜单导航结构

实现菜单导航结构 1.导入字体图标库需要的文件 2.修改引用路径iconfont.css 3.导入到App.vue中 <style>import url(./static/font/iconfont.css); </style>导航区域代码 VUE代码 <template><view class"home"><!-- 导航区域 --><…

Rust SQLx CLI 同步迁移数据库

上文我们介绍了SQLx及SQLite&#xff0c;并介绍了如何使用代码同步迁移数据库。本文介绍Sqlx cli 命令行工具&#xff0c;介绍如何安装、使用&#xff0c;利用其提供的命令实现数据表同步迁移。Java生态中有flyway, sqlx cli 功能类似&#xff0c;利用命令行工具可以和其他语言…

【天地图】HTML页面实现车辆轨迹、起始点标记和轨迹打点的完整功能

目录 一、功能演示 二、完整代码 三、参考文档 一、功能演示 运行以后完整的效果如下&#xff1a; 点击开始&#xff0c;小车会沿着轨迹进行移动&#xff0c;点击轨迹点会显示经纬度和时间&#xff1a; 二、完整代码 废话不多说&#xff0c;直接给完整代码&#xff0c;替换…

鸿蒙学习自由流转与分布式运行环境-价值与架构定义(1)

文章目录 价值与架构定义1、价值2、架构定义 随着个人设备数量越来越多&#xff0c;跨多个设备间的交互将成为常态。基于传统 OS 开发跨设备交互的应用程序时&#xff0c;需要解决设备发现、设备认证、设备连接、数据同步等技术难题&#xff0c;不但开发成本高&#xff0c;还存…

如何启动 Docker 服务:全面指南

如何启动 Docker 服务:全面指南 一、Linux 系统(以 Ubuntu 为例)二、Windows 系统(以 Docker Desktop 为例)三、macOS 系统(以 Docker Desktop for Mac 为例)四、故障排查五、总结Docker,作为一种轻量级的虚拟化技术,已经成为开发者和运维人员不可或缺的工具。它允许用…

Mac启动服务慢问题解决,InetAddress.getLocalHost().getHostAddress()慢问题。

项目启动5分钟&#xff0c;很明显有问题。像网上其他的提高jvm参数就不说了&#xff0c;应该不是这个问题&#xff0c;也就快一点。 首先找到自己的电脑名称&#xff08;用命令行也行&#xff0c;只要能找到自己电脑名称就行&#xff0c;这里直接在共享里看&#xff09;。 复制…

实时美颜直播APP开发指南:美颜sdk与美颜api的应用实践

本篇文章&#xff0c;小编将探讨如何在直播APP中实现实时美颜功能&#xff0c;重点介绍美颜sdk与api的应用实践。 一、什么是实时美颜技术&#xff1f; 实时美颜技术&#xff0c;通常通过图像处理算法&#xff0c;基于主播或用户的实时视频流&#xff0c;进行面部特征的优化。…

【纯原生js】原生实现h5落地页面中的单选组件按钮及功能

h5端的按钮系统自带的一般都很丑&#xff0c;需要我们进行二次美化&#xff0c;比如单选按钮复选框之类的&#xff0c;那怎么对其进行html和css的改造&#xff1f; 实现效果 实现代码 <section id"tags"><h2>给景区添加标题</h2><label><…

win10系统安装docker-desktop

1、开启Hyper-v ———————————————— Hyper-V 是微软提供的一种虚拟化技术&#xff0c;它允许你在同一台物理计算机上运行多个独立的操作系统实例。这种技术主要用于开发、测试、以及服务器虚拟化等领域。 —————————————————————— &#…

阿里云人工智能平台(PAI)免费使用教程

文章目录 注册新建实例交互式建模(DSW)注册 注册阿里云账号进行支付宝验证 新建实例 选择资源信息和环境信息,填写实例名称 资源类型需要选择公共资源,才能使用资源包进行抵扣。目前每月送250计算时。1 * NVIDIA A10 8 vCPU 30 GiB 1 * 24 GiB1 * NVIDIA V100 8 vCPU 32 Gi…

TongRDS分布式内存数据缓存中间件

命令 优势 支持高达10亿级的数据缓冲&#xff0c;内存优化管理&#xff0c;避免GC性能劣化。 高并发系统设计&#xff0c;可充分利用多CPU资源实现并行处理。 数据采用key-value多索引方式存储&#xff0c;字段类型和长度可配置。 支持多台服务并行运行&#xff0c;服务之间可互…

即时通讯| IM+RTC在AI技术加持下的社交体验

即时通讯作为互联网的重要应用之一&#xff0c;见证了中国互联网30年发展的辉煌历程。 它从最初的文字交流&#xff0c;发展到如今的语音、视频通话&#xff0c;甚至是虚拟现实社交&#xff0c;已经渗透到生活的社交、娱乐、商务等方方面面&#xff0c;成为现代社会不可或缺的一…

Redis(5):哨兵

一、作用和架构 1. 作用 在介绍哨兵之前&#xff0c;首先从宏观角度回顾一下Redis实现高可用相关的技术。它们包括&#xff1a;持久化、复制、哨兵和集群&#xff0c;其主要作用和解决的问题是&#xff1a; 1&#xff09;持久化&#xff1a;持久化是最简单的高可用方法(有时甚…

Linux -初识 与基础指令1

博客主页&#xff1a;【夜泉_ly】 本文专栏&#xff1a;【Linux】 欢迎点赞&#x1f44d;收藏⭐关注❤️ 文章目录 &#x1f4da; 前言&#x1f5a5;️ 初识&#x1f510; 登录 root用户&#x1f465; 两种用户➕ 添加用户&#x1f9d1;‍&#x1f4bb; 登录 普通用户⚙️ 常见…

【娱乐项目】基于批处理脚本与JavaScript渲染视频列表的Web页面

Demo介绍 一个简单的视频播放器应用&#xff0c;其中包含了视频列表和一个视频播放区域。用户可以通过点击视频列表中的项来选择并播放相应的视频&#xff0c;播放器会自动播放每个视频并在播放完毕后切换到下一个视频。本项目旨在通过自动化脚本和动态网页渲染&#xff0c;帮助…

k8s集成skywalking

如果能科学上网的话&#xff0c;安装应该不难&#xff0c;如果有问题可以给我留言 本篇文章我将给大家介绍“分布式链路追踪”的内容&#xff0c;对于目前大部分采用微服务架构的公司来说&#xff0c;分布式链路追踪都是必备的&#xff0c;无论它是传统微服务体系亦或是新一代…

使用Native AOT发布C# dll 提供给C++调用

Native AOT&#xff0c;即提前本地编译&#xff08;Ahead-Of-Time Compilation&#xff09;&#xff0c;是一种将托管代码&#xff08;如 C#&#xff09;编译为本机可执行文件的技术&#xff0c;无需在运行时进行任何代码生成。 &#xff08;Native AOT 优缺点截图摘自张善友博…

QT:多ui界面显示

文章目录 1.多ui界面添加2.跳转函数3.返回函数4.Qt5源码工程5.模态显示 1.多ui界面添加 最终生成这个目录 2.跳转函数 void MainWindow::on_pushButton_clicked() {//this->setWindowModality(Qt::WindowModal);test1 *t1 new test1();t1->setParentData(this);this-…

cesium 3dtile ClippingPlanes 多边形挖洞ClippingPlaneCollection

原理就是3dtiles里面的属性clippingPlanes 采用ClippingPlaneCollection&#xff0c;构成多边形来挖洞。 其次就是xyz法向量挖洞 clippingPlanes: new this.ffCesium.Cesium.ClippingPlaneCollection({unionClippingRegions: true, // true 表示多个切割面能合并为一个有效的…

【Python网络爬虫笔记】2-HTTP协议中网络爬虫需要的请求头和响应头内容

1 HTTP 协议整理 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;即超文本传输协议&#xff0c;是用于从万维网&#xff08;WWW&#xff09;服务器传输超文本到本地浏览器的传送协议&#xff0c;直白点儿&#xff0c;就是浏览器和服务器之间的数据交互就是通过 HTT…