滑动窗口(8)_最小覆盖字串

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

滑动窗口(8)_最小覆盖字串

收录于专栏【经典算法练习
本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1. 题目链接:

2. 题目描述 :

3. 解法 :

    解法一(暴力枚举) + 哈希表 :

    算法思路 :

    代码展示 :

    结果分析 :

    对暴力算法的反思与优化 :

    解法二(滑动窗口) :

    算法思路 :

    算法流程 :

    代码展示 :

    结果分析 :

4. 总结


1. 题目链接:

OJ链接:最小覆盖字串

2. 题目描述 :

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

示例 2:

输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。

示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

提示:

  • m == s.length
  • n == t.length
  • 1 <= m, n <= 105
  • s 和 t 由英文字母组成

3. 解法 :

    解法一(暴力枚举) + 哈希表 :

    算法思路 :

1. 用两层循环遍历整个数组

2. 用两个哈希表分别存储s和t的字符

3 当s的哈希表全部包含t哈希表中的数据,返回有效长度

4. 内层循环回退,外层循环++,进入下一层循环

5. 返回对有效长度取min的最后一个值即为我们所需的最小覆盖字串

 

    代码展示 :

class Solution {bool check(int a[], int b[]){for(int i = 0; i < 128; i++)if(b[i] > a[i]) return false;return true;}
public:string minWindow(string s, string t) {int minlen = INT_MAX, left = 0;int hash1[128] = {0};int flag = 1;for(auto ch : t)hash1[ch]++;for(int i = 0; i < s.size(); i++){int hash2[128] = {0};for(int j = i; j < s.size(); j++){hash2[s[j]]++;if(check(hash2, hash1)) {flag = 0;if(j - i + 1 < minlen){minlen = j - i + 1;left = i;} break;}}}if(flag) return "";else return s.substr(left, minlen);}
};

 

    结果分析 :

不出所料,由于题目中字符串s和t的长度达到了10^5,我们的暴力枚举时间复杂度为O(N^2),整体的数据级别达到了10^10,计算机无法在1s之内完成,会给出超出时间限制的错误

    对暴力算法的反思与优化 :

1. check函数

我们其实可以发现我们的check函数在这道题中对我们的时间复杂度有很大的影响:
我们每比较一次就需要在check函数中遍历128次,所以我们的整体时间复杂度为128*10^10,这个就可以采用变量替换我们的check函数

2. 两层循环

我们能不能将两层循环优化成一层呢?不需要再让j移动一段距离后又重新回到i的位置,采用滑动窗口的方法,让[i,j]这个区间是合法区间

 check函数优化

我们这里舍去了check函数,改用len和count统计:
len统计hash1中有效字符的数量

count统计hash2中有效字符的数量

注意:这里两个变量统计的是字符数量而不是个数是因为t字符可能会重复,比如:AAC 

class Solution {public:string minWindow(string s, string t) {int minlen = INT_MAX, left = 0, len = 0;int hash1[128] = {0};int flag = 1;for(auto ch : t){if(hash1[ch] == 0) len++;hash1[ch]++;}for(int i = 0; i < s.size(); i++){int hash2[128] = {0}, count = 0;for(int j = i; j < s.size(); j++){hash2[s[j]]++;if(hash2[s[j]] == hash1[s[j]]) count++;if(count == len) {flag = 0;if(j - i + 1 < minlen){minlen = j - i + 1;left = i;} break;}}}if(flag) return "";else return s.substr(left, minlen);}
};

 

比之前多通过了一个例子,看来我们得优化还是有效果的

不过最后还是没能通过这道题主要是因为我们的暴力循环根本时间复杂度为O(N^2),这个改不掉的,所以接下来我们要对暴力算法的两层循环进行优化,将其优化成一层循环就能解决. 

    解法二(滑动窗口) :

    算法思路 :

研究对象是连续的区间,因此可以尝试使用滑动窗口的思想来解决

如何判断当前窗口内的所有字符是符合要求的呢?

我们可以使用两个哈希表, 其中一个将目标串的信息统计起来,另一个哈希表的动态的维护窗口内字符串的信息.

当动态哈希表中包含目标串中所有的字符,并且对应的个数都不小于目标串的哈希表中各个字符的个数,那么当前窗口就是一种可行的方案

    算法流程 :

1. 定义两个全局的哈希表: 1号哈希表hash1用来记录字串的信息,2号哈希表hash2用来记录目标串t的信息;

2. 实现一个接口函数,判断当前窗口是否满足要求:

        遍历两个哈希表中对应的元素:

                如果t中某个字符的数量大于窗口字符的数量,也就是2号哈希表某个位置大于1号哈希表.说明不匹配,返回false

                如果全匹配返回true

    代码展示 :

class Solution {
public:string minWindow(string s, string t) {int hash1[128] = {0}, hash2[128] = {0};int len = 0, minlen = INT_MAX, begin = -1;for(auto ch : t)if(hash1[ch]++ == 0) len++;for(int left = 0, right = 0, count = 0; right < s.size(); right++){if(++hash2[s[right]] == hash1[s[right]]) count++;while(count == len){if(right - left + 1 < minlen){minlen = right - left + 1;begin = left;}if(hash2[s[left]]-- == hash1[s[left]]) count--;left++;}}return begin == -1 ? "" : s.substr(begin, minlen);}
};

 

    结果分析 :

这段代码的时间复杂度分析如下:

初始化字符计数:遍历字符串 t,计算每个字符的频率,时间复杂度为
O(m),其中m 是字符串 t 的长度。

双指针遍历字符串 s:

外层 for 循环遍历字符串 s,时间复杂度为O(n)其中n 是字符串 s 的长度。
内层 while 循环在最坏情况下会遍历字符串 s,但由于 left 和 right 只会各自移动一次,因此总体上 while 循环也可以认为是O(n)

综合以上分析,整体的时间复杂度为:
O(m + n)

这里m 是字符串 t 的长度,n 是字符串 s 的长度。这个复杂度是非常高效的,适合处理较大的输入。

4. 总结

这一道题是滑动窗口完结篇,滑动窗口完结撒花!!!

滑动窗口这个一个专栏共8道题,希望能帮助大家彻底掌握滑动窗口

下个算法专栏就是二分算法

对算法感兴趣的宝子们赶紧点赞收藏起来吧!!!我们明天见!!!

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

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

相关文章

【C++指南】inline内联函数详解

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 目录 引言 C为什么引入了inline来替代C语言中的宏 inline的基本用法 定义inline函数 inline的优势与…

Why is OpenAI image generation Api returning 400 bad request in Unity?

题意&#xff1a;为什么 OpenAI 图像生成 API 在 Unity 中返回 400 Bad Request 错误&#xff1f; 问题背景&#xff1a; Im testing out dynamically generating images using OpenAI API in Unity. Amusingly, I actually generated most of this code from chatGPT. 我正在…

选择优质代理IP建议分享

“在互联网的广阔世界中&#xff0c;代理IP作为一种重要的网络工具&#xff0c;扮演着连接用户与目标服务器之间的桥梁角色。不同类型的代理IP适用于不同的场景和需求&#xff0c;因此选择合适的代理IP类型对于提高网络访问效率、保护用户隐私至关重要。” 一、代理IP类型概述 …

感谢老美苦苦相逼,逼出华为鸿蒙PC

文&#xff5c;琥珀食酒社 作者 | 随风 哎&#xff0c;告诉大家一个不好的消息 刚刚余总说 Windows PC是最后一批了 因为美国新一轮制裁又来了 但大家别急 再告诉大家一个好消息 那就是我们的鸿蒙PC要来了 今天不是华为三折叠手机和iPhone 16首发吗 估计老美是前端时间…

MySQL高阶1873-计算特殊奖金

目录 题目 准备数据 分析数据 总结 题目 编写解决方案&#xff0c;计算每个雇员的奖金。如果一个雇员的 id 是 奇数 并且他的名字不是以 M 开头&#xff0c;那么他的奖金是他工资的 100% &#xff0c;否则奖金为 0 。 返回的结果按照 employee_id 排序。 准备数据 Crea…

Java设计模式——简单工厂模式(完整详解,附有代码+案例)

文章目录 5.2简单工厂模式5.2.1 概述5.2.2 结构5.2.3 实现5.2.4 优缺点5.2.5 扩展—静态工厂 5.2简单工厂模式 5.2.1 概述 简单工厂不是一种设计模式&#xff0c;反而比较像是一种编程习惯。 不属于GOF的23种经典设计模式 5.2.2 结构 简单工厂包含下角色&#xff1a; 抽象…

ISSTA 2024现场精彩:“杰出论文奖”超半数属于中国学者

ISSTA会议是软件工程领域中最具影响力的国际会议之一&#xff0c;也是中国计算机学会&#xff08;CCF&#xff09;推荐的A类会议。 第33届ISSTA会议已于奥地利维也纳圆满结束&#xff0c;这场盛会已经吸引了众多来自学术界和工业界的软件测试专家、研究人员和工程师&#xff0c…

doris数据库的坑:第二弹

上一篇文章《doris数据库操作数字遇到的问题》是第一弹&#xff0c;文章结尾提到过doris不支持with语句&#xff0c;其实是因为我自己没找到正确使用的方式导致的。昨天因为客户现场有一个解析SQL的接口提示异常&#xff0c;所以就开始了长路漫漫的排查之旅。不过首先承认及纠正…

英飞凌 PSoC6 RT-Thread 评估板硬件概览

PSoC™ 62 with CAPSENSE™ evaluation kit 开发板&#xff08;以下简称 PSoC 6 RTT 开发板&#xff09;是英飞凌&#xff08;Infineon&#xff09;联合 RT-Thread 发布一款面向物联网开发者的 32 位双核 MCU 开发套件&#xff0c;其默认内置 RT-Thread 物联网操作系统。本文主…

vue 入门一

参考&#xff1a;丁丁的哔哩哔哩 1.使用vue 1.1 使用CDN的方式使用Vue mount和<div id"counter">关联起来 1.2 vue中的createApp import { createApp } from "vue"; import App from "./App.vue"; createApp(App).mount("#app&qu…

C#基础(15)选择排序

前言 上一节中我们已经学习了第一个算法&#xff1a;冒泡算法&#xff0c;相信你也有足够的自信继续学习更多的算法。 今天我们就来讲解又一个排序相关的算法&#xff1a;选择排序。 时间复杂度 在进行今天的排序算法讲解之前&#xff0c;我们先补充一个知识点&#xff1a…

单链表(c语言简单实现)

单链表是一种常见的数据结构 一、结构特点 1. 由一系列节点组成&#xff0c;每个节点包含数据域和指向下一个节点的指针域。 2. 最后一个节点的指针域为 null&#xff0c;表示链表的结尾。 二、主要操作 1. 插入节点&#xff1a;可以在链表的头部、尾部或特定位置插入新节点。…

Docker安装rabbitmq并配置延迟队列

下载rabbitmq镜像 docker pull rabbitmq:management 运行rabbitmq镜像 docker run -id --namerabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 -e RABBITMQ_DEFAULT_USERtom -e RABBITMQ_DEFAULT_PASStom rabbitmq:management …

windows环境下MySQL启动失败 查看data文件夹中.err发现报错unknown variable ‘log‐bin=mysql‐bin‘

文章目录 问题解决方法 问题 今天在windows环境下配置MySQL主从同步&#xff0c;在修改my.ini文件后发现MySQL启动失败了 打开my.ini检查参数发现没有问题 [mysqld] #开启二进制日志&#xff0c;记录了所有更改数据库数据的SQL语句 log‐bin mysql‐bin #设置服务id&#x…

电子束光刻过程中的场拼接精度

以下内容如有错误&#xff0c;请不吝指教&#xff0c;感谢&#xff01; 1、EBL为什么会出现场拼接误差&#xff0c;如何解决&#xff1f; ChatGPT 说&#xff1a; 在电子束光刻&#xff08;EBL&#xff09;过程中&#xff0c;SOI&#xff08;硅绝缘体&#xff09;芯片上出现*…

操作系统 | 学习笔记 | | 王道 | 5.2 设备独立软件

5.2 设备独立性软件 IO核心子系统 磁盘IO也属于IO调度问题 5.2.1 与设备无关的软件 与设备无关的软件是I/O系统的最高层软件&#xff0c;它的下层是设备驱动程序。 设备保护&#xff1a; 操作系统需要实现文件保护功能&#xff0c;不同的用户对各个文件有不同的访问权限&am…

2024.9.20 作业

写一个shell脚本&#xff0c;将以下内容放到脚本中&#xff1a; a.在家目录下创建目录文件&#xff0c;dir b.dir下创建dir1和dir2 c.把当前目录下的所有文件拷贝到dir1中&#xff0c; d.把当前目录下的所有脚本文件拷贝到dir2中 e.把dir2打包并压缩为dir2.tar.xz f.再把…

VSCode开发ros程序无法智能提示的解决方法(一)

VSCode开发ros程序无法智能提示的解决方法&#xff08;一&#xff09; 问题解决 问题 在Ubuntu下使用vscode开发ros程序&#xff0c;无法进行智能提示。 解决 将 intelli Sense Engine 设置为 Tag Parser 即可。

SpringBoot实现OAuth客户端

背景 5 月份的时候&#xff0c;我实践并整理了一篇博客&#xff1a;SpringBoot搭建OAuth2&#xff0c;该博客完成之后&#xff0c;本以为能对OAuth2的认证机制更加清晰&#xff0c;但我却觉得自己更“迷惘”了。 抛开我在项目中积累的浅薄经验不谈&#xff0c;单从在网…

智慧园区的发展趋势

在数字经济高速发展、前瞻技术加速创新和社会需求革命的驱动下&#xff0c;江园科技智慧园区的未来发展将呈现数智化、融合化、人本化、韧性化和绿色化五大趋势。 趋势一&#xff1a;数智化 以万兆联接、数字平台为特征的基础设施将成为园区的核心底座。以 5.5G/NET5.5G/F5.5G…