【LeetCode 热题100】76. 最小覆盖子串的算法思路及python代码
76. 最小覆盖子串
给你一个字符串 s s s、一个字符串 t t t。返回 s s s 中涵盖 t t t 所有字符的最小子串。如果 s s s 中不存在涵盖 t t t 所有字符的子串,则返回空字符串 ‘ ‘ " ``\quad" ‘‘" 。
注意:
- 对于 t t t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t t t 中该字符数量;
- 如果 s s 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 的子串中,
因此没有符合条件的子字符串,返回空字符串。
个人解题思路:
我们可以利用“滑动窗口”的思想来解决这个问题。 具体步骤如下:
初始化:
- 创建一个字典
remaining_target,记录字符串 t 中每个字符的出现次数。 - 定义两个指针
index和temp_index,表示当前窗口的左右边界。 - 定义变量
current_substring,用于记录当前窗口的子串。 - 定义变量
min_substring,用于记录最小子串。 - 定义变量
min_substring_length,用于记录最小子串的长度。 - 定义布尔变量
found_all_chars,表示是否已找到目标字符串的所有字符。
遍历字符串:
代码首先初始化了目标字符串 t 的临时变量 remaining_target,并设置了变量来记录当前子串和最小子串。接着,代码遍历源字符串 s,对每个字符进行判断它是否在 remaining_target 中。如果在,则表示找到了目标字符串中的一个字符,remaining_target 中对应字符的数量减一。当在s 中找到第一个 t 的元素时,代码记录下当前的索引 temp_index,以备后续滑动index使用。 在遍历过程中,代码不断更新当前子串 current_substring,并在满足条件时更新最小子串 min_substring。当 remaining_target 的长度为零时,说明当前窗口已经包含了目标字符串的所有字符,代码会通过调整索引来优化子串的长度。最终,代码返回找到的最小子串。
python代码:
class Solution:def minWindow(self, s: str, t: str) -> str:# 初始化目标字符串的副本remaining_target = t# 初始化当前子串和最小子串current_substring = ''min_substring = ''min_substring_length = len(s)# 标记是否已找到目标字符串的所有字符found_all_chars = Falseindex = 0# 如果源字符串的长度小于目标字符串,直接返回空字符串if len(s) < len(t):return ''# 遍历源字符串while index < len(s):current_char = s[index]index += 1# 如果当前字符在目标字符串中if current_char in remaining_target:found_all_chars = True# 删除目标字符串中对应的字符remaining_target = remaining_target.replace(current_char, '', 1)# 如果目标字符串中剩余字符的长度为目标字符串长度减一,记录当前索引if len(remaining_target) == len(t) - 1:temp_index = index# 如果已找到目标字符串的所有字符if found_all_chars:current_substring += current_char # 将当前字符添加到当前子串# 如果目标字符串的所有字符都已找到且当前子串长度小于最小子串长度if len(remaining_target) == 0 and len(current_substring) <= min_substring_length:min_substring = current_substringmin_substring_length = len(min_substring)# 如果目标字符串的所有字符都已找到if len(remaining_target) == 0:index = temp_indexremaining_target = tfound_all_chars = Falsecurrent_substring = ''return min_substring
时间复杂度:
- 时间复杂度: O ( n ) O(n) O(n), 其中 n 是字符串 s s s 的长度。
由于每个字符最多被指针 index 访问一次,因此时间复杂度为 O ( n ) O(n) O(n)。 - 空间复杂度: O ( k ) O(k) O(k), 其中 k 是字符集 t t t 的大小。
需要额外的空间来存储字符串remaining_target和current_substring,其大小与字符集的大小成正比。
结果
python3的代码在用例165/168处提示超时,因此我用deepseek将代码转成了C++的形式提交了。以下是C++的提交结果和代码(C++的代码我没有检查):

#include <string>
#include <unordered_map>
#include <algorithm>class Solution {
public:std::string minWindow(std::string s, std::string t) {// 统计 t 中每个字符的出现次数std::unordered_map<char, int> t_count;for (char c : t) {t_count[c]++;}// 记录当前窗口内每个字符的出现次数std::unordered_map<char, int> window_count;int required = t_count.size(); // 需要匹配的字符种类数int formed = 0; // 当前窗口内已匹配的字符种类数int left = 0, right = 0; // 滑动窗口的左右指针int min_len = s.size() + 1; // 最小窗口的长度int min_left = 0; // 最小窗口的左指针while (right < s.size()) {// 扩展窗口char c = s[right];window_count[c]++;if (t_count.find(c) != t_count.end() && window_count[c] == t_count[c]) {formed++;}// 收缩窗口while (left <= right && formed == required) {c = s[left];if (right - left + 1 < min_len) {min_len = right - left + 1;min_left = left;}window_count[c]--;if (t_count.find(c) != t_count.end() && window_count[c] < t_count[c]) {formed--;}left++;}right++;}return min_len == s.size() + 1 ? "" : s.substr(min_left, min_len);}
};
官方解题思路
其核心思想也是使用滑动窗口的思想,结合哈希表来找到字符串 s s s 中包含字符串 t t t 所有字符的最小子串。
初始化:
- 使用
unordered_map ori来记录目标字符串t中每个字符的出现次数。 - 定义两个指针
l和r,分别表示当前窗口的左边界和右边界。 - 定义变量
len来记录当前找到的最小子串的长度,ansL和ansR分别记录最小子串的起始和结束位置。
遍历字符串:
首先,右指针 r 向右移动,扩展窗口,直到窗口包含目标字符串 t 中的所有字符。每次右指针移动时,更新当前窗口中字符的计数。当窗口包含了 t 中所有字符时,尝试通过移动左指针 l 来收缩窗口,寻找更小的覆盖子串。每次收缩时,更新当前窗口中字符的计数。在每次收缩窗口时,检查当前窗口的大小是否小于之前记录的最小子串长度。如果是,则更新最小子串的起始和结束位置。遍历完成后,返回从 ansL 到 ansR 的子串。如果未找到符合条件的子串,则返回空字符串。
class Solution {
public:unordered_map <char, int> ori, cnt;bool check() {for (const auto &p: ori) {if (cnt[p.first] < p.second) {return false;}}return true;}string minWindow(string s, string t) {for (const auto &c: t) {++ori[c];}int l = 0, r = -1;int len = INT_MAX, ansL = -1, ansR = -1;while (r < int(s.size())) {if (ori.find(s[++r]) != ori.end()) {++cnt[s[r]];}while (check() && l <= r) {if (r - l + 1 < len) {len = r - l + 1;ansL = l;}if (ori.find(s[l]) != ori.end()) {--cnt[s[l]];}++l;}}return ansL == -1 ? string() : s.substr(ansL, len);}
};
时间复杂度:
- 时间复杂度: O ( n ) O(n) O(n), 其中 n 是字符串 s 的长度。
由于每个字符最多被指针l和r各访问一次,因此时间复杂度为 O ( n ) O(n) O(n)。 - 空间复杂度: O ( k ) O(k) O(k), 其中
k是字符集的大小。
需要额外的空间来存储哈希表ori,其大小与字符集的大小成正比。
结果

算法分析
同样的思路,我的算法要比官方题解效率更高,主要可能有以下两方面的原因:
数据结构的选择:
官方题解: 使用了 unordered_map 来记录字符的出现次数。
我的算法: 使用了更高效的数据结构,即临时变量和数组。
影响: 对于字符集大小固定的情况,使用临时变量数组可以减少哈希计算的开销,从而提高效率。
字符串操作:
官方题解: 每次收缩窗口时,会频繁地进行字符串截取操作。
我的算法:通过记录子串的起始位置和长度,避免了多次字符串截取。
影响: 减少字符串操作可以降低时间复杂度,提升性能。
相关文章:
【LeetCode 热题100】76. 最小覆盖子串的算法思路及python代码
76. 最小覆盖子串 给你一个字符串 s s s、一个字符串 t t t。返回 s s s 中涵盖 t t t 所有字符的最小子串。如果 s s s 中不存在涵盖 t t t 所有字符的子串,则返回空字符串 ‘ ‘ " \quad" ‘‘" 。 注意: 对于 t t t 中重复…...
力扣-回溯-17 电话号码的字母组合
思路 和之前的回溯不同的是,要遍历完所有的数字,并且在单层递归逻辑里需要遍历一整个字符串 代码 class Solution { public:vector<string> letters {"", "", "abc", "def", "ghi", "…...
[AHOI2018初中组] 分组---贪心算法
贪心没套路果真如此。 题目描述 小可可的学校信息组总共有 n 个队员,每个人都有一个实力值 ai。现在,一年一度的编程大赛就要到了,小可可的学校获得了若干个参赛名额,教练决定把学校信息组的 n 个队员分成若干个小组去参加这场…...
知识图谱-学习计划
✨知识图谱知识学习,给我点赞!🌟🌟🌟 🌟什么是知识图谱? 知识图谱是一种通过图结构表示知识的技术,它可以帮助我们更清晰地理解和组织信息。无论是学习、工作还是生活,知…...
网安作业3
标准版 接口ip配置 r2 [r2]interface GigabitEthernet 0/0/0 [r2-GigabitEthernet0/0/0]ip address 13.0.0.3 24 [r2-GigabitEthernet0/0/0]interface GigabitEthernet 0/0/1 [r2-GigabitEthernet0/0/1]ip address 100.1.1.254 24 [r2-GigabitEthernet0/0/1]interface Gigab…...
快速提升网站收录:内容创作的艺术
快速提升网站收录,内容创作是关键。以下是一些关于内容创作以提升网站收录的艺术性建议: 一、关键词研究与优化 选择长尾关键词:进行深入的关键词研究,选择既符合网站主题又具有一定搜索量的长尾关键词。这些关键词通常更具体&a…...
【C语言】CreateFile函数用法介绍
目录 一、函数原型与基本功能 二、参数详解 1. lpFileName(文件路径) 2. dwDesiredAccess(访问权限) 补充说明 3. dwShareMode(共享模式) 5. dwCreationDisposition(创建策略)…...
蓝桥杯好数
样例输入: 24 输出:7 输入:2024 输出: 150 思路:本题朴素方法的时间复杂度是O(n * log10(n)) ,不超时。主要考察能否逐位取数,注意细节pi,这样不会改变i,否则会导致循环错误。 #in…...
SOME/IP--协议英文原文讲解10
前言 SOME/IP协议越来越多的用于汽车电子行业中,关于协议详细完全的中文资料却没有,所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块: 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.2.2 Req…...
欢乐力扣:赎金信
文章目录 1、题目描述2、 代码 1、题目描述 赎金信,给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。如果可以,返回 true ;否则返回 false 。magazine 中的每个字符只能在…...
【量化科普】Standard Deviation,标准差
【量化科普】Standard Deviation,标准差 🚀🚀🚀量化软件开通🚀🚀🚀 🚀🚀🚀量化实战教程🚀🚀🚀 在量化投资领域…...
stm32单片机个人学习笔记15(I2C通信协议)
前言 本篇文章属于stm32单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。 STM32入门教程-2023版 细…...
网络安全防护
一:物理安全防护 直接的物理破坏所造成的损失远大于通过网络远程攻击 提高物理安全需关注的问题: 1: 服务器和安全设备是否放置在上锁的机房内? 2: 网络设备是否被保护和监控? 3: 是否有无关人员单独在敏感区域工作&…...
YOLOV7的复现过程
复现 YOLOv7 代码的步骤相对清晰,主要分为以下几个部分: 环境准备克隆 YOLOv7 仓库准备数据集训练模型验证和测试推理(Inference) 下面是一个简化的流程来帮助你复现 YOLOv7 代码: 1. 环境准备 首先,你…...
uniapp实现app的pdf预览
实现效果 文件准备 static下添加该pdf文件(下载地址:https://gitee.com/shallow-winds/resource_package/tree/master/%E6%96%B9%E6%B3%95%E4%B8%80/html) 使用web-view进行展示: 在这里插入代码片 <web-view :src"u…...
用Java创建一个验证码的工具类
在Java中创建一个验证码工具类,可以通过以下代码实现。该工具类支持生成包含字母和数字的随机验证码图片,并添加干扰线和噪点以提高安全性。以下是详细实现: 完整代码实现 import javax.imageio.ImageIO; import java.awt.*; import java.aw…...
uvm中的激励是如何发送出去的
在UVM中,Sequence生成的激励(Transaction)通过以下协作流程发送到Driver并最终驱动到DUT,其核心机制如下: --------------- --------------- ------------ ----- | Sequence | → | Seque…...
一只企鹅如何改变世界
一、历史的转折点:一只企鹅如何改变世界 1991年,芬兰大学生Linus Torvalds在邮件列表中写道:“我正在做一个自由的操作系统(只是爱好,不会像GNU那样庞大专业)”。这个后来被称为Linux内核的项目,与GNU项目的结合,点燃了开源运动的燎原之火。 关键演化: 1996年:Tux企…...
拦截器VS过滤器:Spring Boot中请求处理的艺术!
目录 一、拦截器(Interceptor)和过滤器(Filter):都是“守门员”!二、如何实现拦截器和过滤器?三、拦截器和过滤器的区别四、执行顺序五、真实的应用场景六、总结 🌟如果喜欢作者的讲…...
C语言预处理学习笔记
1. 预处理器的功能 预处理器(Preprocessor)在编译C语言程序之前对源代码进行预处理。预处理指令以#号开头,主要包括文件包含、宏定义、条件编译等功能。 2. 文件包含 文件包含功能用于在一个文件中包含另一个文件的内容,通常用…...
什么是DSP? ESP32 有DSP吗?
DSP 是 Digital Signal Processor 的缩写,中文全称为 “数字信号处理器”。 简单来说,DSP 是一种专门为了极快地处理数学算法而设计的微处理器。如果说 CPU(中央处理器)是一个什么都能干的“全才经理”,那么 DSP 就是一个“数学天才”或“计算专家”。 以下是关于 DSP 的…...
ChatGPT机器翻译优化指南:温度、提示词与避坑实践
1. 项目概述与核心价值最近在机器翻译(Machine Translation, MT)领域,一个绕不开的话题就是如何用好以ChatGPT为代表的大语言模型。我自己在尝试将GPT-3.5/4集成到翻译工作流中时,遇到了不少困惑:为什么有时候翻译质量…...
WorkflowAI:开源LLM协作平台,让AI应用开发从周级缩短到分钟级
1. 项目概述与核心理念如果你正在为如何将大语言模型(LLM)的能力快速、可靠地集成到你的产品中而头疼,那么WorkflowAI这个项目,绝对值得你花时间深入了解。它不是一个简单的API封装器,而是一个旨在彻底改变产品团队与工…...
XUnity自动翻译器终极指南:5分钟让任何Unity游戏变中文版
XUnity自动翻译器终极指南:5分钟让任何Unity游戏变中文版 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 还在为外语游戏而烦恼吗?XUnity自动翻译器是你的终极解决方案!…...
第一个作业
我是一名大一新生,现在刚开始学习编程C语言,我学习编程不仅是为了学校的考试,更想精通编程语言,使之成为自己得力的助手。我打算每日都练习一点编程,除了自学教材,还会结合B站上的视频进行学习,…...
Qwen3.5-2B数据库智能查询实战:自然语言转SQL语句
Qwen3.5-2B数据库智能查询实战:自然语言转SQL语句 1. 引言:当业务人员遇到数据库查询难题 市场部的王经理每周都要找IT部门要销售数据报表。"帮我查下上个月卖得最好的产品"、"看看华东区哪些客户三个月没下单了"——这些看似简单…...
数据结构入门:栈实现全解析
个人专栏:《数据结构-初阶》《经典OJ题目》《C语言》 欢迎各位大佬交流! 目录 一、栈的概念及结构 1、栈的基本概念 2、栈的结构 二、代码实现 0、初始化 1、入栈 2、出栈 3、返回栈顶元素 4、获取栈中有效元素个数 5、检测栈是否为空 6、销毁…...
开源应用平台Budibase:从低代码到企业级自托管部署全解析
1. 项目概述:从“低代码”到“开源应用平台”的认知跃迁第一次听说Budibase,很多人会下意识地把它归类到“又一个低代码工具”的范畴里。毕竟,市面上打着“拖拽式开发”、“快速构建应用”旗号的产品实在太多了。但当你真正深入使用Budibase&…...
神经网络在NLP中的应用与Transformer实现详解
1. 神经网络模型在自然语言处理中的核心价值 第一次接触自然语言处理(NLP)时,我被传统基于规则的方法折磨得够呛——那些复杂的语法解析树和手工设计的特征模板,就像试图用乐高积木搭建一座摩天大楼。直到2013年Mikolov提出word2vec,神经网络…...
Learning to AutoFocus:深度学习驱动的自动对焦实战
文章目录 Learning to AutoFocus:深度学习驱动的自动对焦实战 一、问题背景 二、技术方案 三、数据准备 四、模型 五、训练 六、推理与对焦控制 七、部署考虑 八、实验结果 九、总结 代码链接与详细流程 购买即可解锁1000+YOLO优化文章,并且还有海量深度学习复现项目,价格仅…...
