力扣最热一百题——最小覆盖子串

目录

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

题目描述

示例

提示:

解法一:滑动窗口

1. 初始化

2. 构建 mapT

3. 滑动窗口

4. checkT 方法

5. 返回结果

Java写法:

运行时间

C++写法:

相比于Java主要改动:

运行时间

时间复杂度和空间复杂度

解法一极限优化

优化说明

运行时间 

总结


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

注:下述题目描述和示例均来自力扣

题目描述

给你一个字符串 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 <= 10^5
  • s 和 t 由英文字母组成


解法一:滑动窗口

1. 初始化

  • 使用两个 HashMapmapS 和 mapT)来记录字符出现的次数。mapT 用于存储字符串 t 中每个字符的出现次数,而 mapS 用于在滑动窗口过程中动态地记录当前窗口内字符的出现次数。
  • 初始化结果子串的起始位置 resStart 为 -1(表示还未找到符合条件的子串),和结果子串的长度 resLen 为 s 的长度加1(确保初始时,任何可能的子串长度都会比这个值小,从而能够更新)。

2. 构建 mapT

  • 遍历字符串 t,统计每个字符的出现次数,并存储在 mapT 中。

3. 滑动窗口

  • 使用两个指针 left 和 right 来表示当前滑动窗口的左右边界。
  • 使用一个 while 循环来移动这两个指针,直到 right 指针超出字符串 s 的范围或当前窗口已经包含了 t 的所有字符(通过 checkT 方法检查)。
  • 在循环内部,首先检查是否需要向右扩展窗口(即移动 right 指针)。如果当前窗口不包含 t 的所有字符(!checkT(mapS, mapT) 为真),则扩展窗口(即将 s.charAt(right) 加入到 mapS 中,并右移 right 指针)。
  • 如果当前窗口已经包含了 t 的所有字符,则尝试通过左移 left 指针来缩小窗口,直到窗口不再包含 t 的所有字符为止。在每次缩小窗口的过程中,都检查并更新结果子串的起始位置和长度(如果当前窗口长度更小的话)。

4. checkT 方法

  • 这个方法用于检查 mapS 是否包含了 mapT 中的所有字符,并且每个字符的出现次数都不少于 mapT 中对应字符的出现次数。
  • 遍历 mapT 中的每个字符,检查其在 mapS 中的出现次数是否满足条件。如果有任何一个字符不满足条件,则返回 false;否则返回 true

5. 返回结果

  • 循环结束后,如果找到了符合条件的子串(即 resStart 不为 -1),则返回该子串;否则返回空字符串 "",表示没有找到符合条件的子串。

Java写法:

class Solution {public String minWindow(String s, String t) {int lenS = s.length();Map<Character,Integer> mapS = new HashMap<>();Map<Character,Integer> mapT = new HashMap<>();int resStart = -1;int resLen = lenS + 1;// 将t中的元素使用map集合存储起来for (int i = 0; i < t.length(); i++) {mapT.put(t.charAt(i),mapT.getOrDefault(t.charAt(i),0) + 1);}int left = 0;int right = 0;while (right < lenS || checkT(mapS, mapT)){if (right > lenS || !checkT(mapS, mapT)){// 如果当前窗口没有包含的话就添加元素,并右移rightmapS.put(s.charAt(right), mapS.getOrDefault(s.charAt(right),0) + 1);right++;}else {// 如果当前窗口包含了的话,判断并更新结果的起始位置和长度if (resLen > (right - left)){resStart = left;resLen = right - left;}// 就删除元素,并右移leftmapS.put(s.charAt(left), mapS.get(s.charAt(left)) - 1);left++;}}if(resStart != -1){return s.substring(resStart, resStart + resLen);}return "";}/*** 检查mapS是否包含了mapT中的全部字符* @return*/private boolean checkT(Map<Character, Integer> mapS, Map<Character, Integer> mapT) {for (Character character : mapT.keySet()) {if (mapT.get(character) > mapS.getOrDefault(character, 0)){return false;}}return true;}
}

运行时间

520送给大家

 

C++写法:


class Solution {
public:std::string minWindow(std::string s, std::string t) {int lenS = s.length();int lenT = t.length();std::unordered_map<char, int> mapS;std::unordered_map<char, int> mapT;// 将t中的元素使用map集合存储起来for (char c : t) {mapT[c]++;}int resStart = -1;int resLen = lenS + 1;int left = 0, right = 0;int required = mapT.size(); // 需要的不同字符数量int formed = 0; // 当前窗口中满足条件的不同字符数量while (right < lenS) {// 添加右指针的字符char c = s[right];mapS[c]++;// 如果当前字符在t中并且频率达标,则形成一个满足条件的字符if (mapT.count(c) && mapS[c] == mapT[c]) {formed++;}// 当当前窗口中包含了所有t的字符时,尝试收缩左指针while (left <= right && formed == required) {c = s[left];// 更新最小子串的长度和位置if (resLen > (right - left + 1)) {resStart = left;resLen = right - left + 1;}// 移除左指针指向的字符,并更新窗口mapS[c]--;if (mapT.count(c) && mapS[c] < mapT[c]) {formed--;}left++;}right++;}// 如果没有找到符合条件的子串,则返回空字符串,否则返回最小子串return resStart != -1 ? s.substr(resStart, resLen) : "";}
};

相比于Java主要改动:

  1. 数据结构:Java 的 HashMap 改为 C++ 的 unordered_map
  2. 字符串处理:Java 的字符串操作改为 C++ 的 string 方法,例如 s.substr
  3. 类型和语法:调整了类型和语法,使其符合 C++ 规范。
  4. 字符计数:在删除字符时,如果计数为 0,使用 erase 方法删除该字符。
  5. 主循环条件:适当调整了 while 循环的条件,以确保在右指针达到字符串末尾时不会越界。

 

运行时间

时间复杂度和空间复杂度


解法一极限优化

我就只写Java了,脑子要炸掉了

优化说明

  1. 窗口逻辑简化:原代码在主循环中条件判断较复杂,优化后将扩展右指针和收缩左指针的逻辑分开,使代码结构更清晰。

  2. 减少 mapS 的使用:在添加和移除字符时,直接更新 mapS 的计数,而不是每次都调用 getOrDefault,提高了性能。

  3. 优化 formed 计数:通过使用 formed 变量来跟踪当前满足条件的字符数量,避免每次调用检查 checkT 方法,减少了不必要的遍历。

  4. 使用数组来存储结果:使用 int[] result 数组来存储最小长度和指针位置,使代码更简洁,易于理解。

class Solution {public String minWindow(String s, String t) {int lenS = s.length(), lenT = t.length();// 如果s的长度小于t的长度,则直接返回空字符串if (lenS < lenT) return "";// 创建mapT,存储t中每个字符的频率Map<Character, Integer> mapT = new HashMap<>();for (char c : t.toCharArray()) {mapT.put(c, mapT.getOrDefault(c, 0) + 1);}// 创建mapS,存储当前窗口s中每个字符的频率Map<Character, Integer> mapS = new HashMap<>();int left = 0, right = 0;int required = mapT.size(); // 需要的不同字符数量int formed = 0; // 当前窗口中满足条件的不同字符数量int[] result = {-1, 0, 0}; // result[0]: 最小长度, result[1]: 左指针位置, result[2]: 右指针位置// 扩展右指针,形成窗口while (right < lenS) {char c = s.charAt(right);mapS.put(c, mapS.getOrDefault(c, 0) + 1);// 如果当前字符在t中,并且频率达到要求,则形成一个满足条件的字符if (mapT.containsKey(c) && mapS.get(c).intValue() == mapT.get(c).intValue()) {formed++;}// 当当前窗口中包含了所有t的字符时,尝试收缩左指针while (left <= right && formed == required) {c = s.charAt(left);// 更新最小子串的长度和位置if (result[0] == -1 || right - left + 1 < result[0]) {result[0] = right - left + 1;result[1] = left;result[2] = right;}// 移除左指针指向的字符,并更新窗口mapS.put(c, mapS.get(c) - 1);// 如果移除后该字符不再满足条件,则减少formed计数if (mapT.containsKey(c) && mapS.get(c).intValue() < mapT.get(c).intValue()) {formed--;}left++;}right++;}// 如果没有找到符合条件的子串,则返回空字符串,否则返回最小子串return result[0] == -1 ? "" : s.substring(result[1], result[2] + 1);}
}

运行时间 

        这优化效果,牛不牛!!!!!


总结

        我真的脑子爆炸了,┭┮﹏┭┮晚安

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

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

相关文章

Hbase日常运维

1 Hbase日常运维 1.1 监控Hbase运行状况 1.1.1 操作系统 1.1.1.1 IO 群集网络IO&#xff0c;磁盘IO&#xff0c;HDFS IO IO越大说明文件读写操作越多。当IO突然增加时&#xff0c;有可能&#xff1a;1.compact队列较大&#xff0c;集群正在进行大量压缩操作。 2.正在执行…

微服务Docker相关指令

1、拉取容器到镜像仓库 docker pull xxx //拉取指令到 镜像仓库 例如 docker pull mysql 、docker pull nginx docker images //查看镜像仓库 2、删除资源 2.1、删除镜像仓库中的资源 docker rmi mysql:latest //删除方式一&#xff1a;格式 docker rmi 要…

安卓系统常见问题如native crash,卡顿卡死定位工具命令技巧-android framework实战开发

背景&#xff1a; 有学员朋友近来有问到一些安卓系统开发过程中的一些核心小技能小技巧等&#xff0c;比如native crash在企业里面该如何准确定位具体代码函数&#xff0c;程序卡住&#xff0c;或者长时间没反应&#xff0c;想要看看卡在代码的哪里。针对以上的一些问题&#…

408选择题笔记|自用|随笔记录

文章目录 B树&#xff1a;访问节点建堆&#xff01;将结点插入空堆广义指令求每个子网可容纳的主机数量虚拟内存的实现方式文件目录项FCB和文件安全性管理级别索引文件三种存取方式及适用器件成组分解访问磁盘次数 C语言标识符 最小帧长物理传输层介质 局域网&广域网考点总…

AIGC基础工具-用于数据分析和数据处理的核心库Pandas介绍

文章目录 1. Pandas 的核心数据结构1.1 Series创建 SeriesSeries 重要属性示例 1.2 DataFrame创建 DataFrameDataFrame 重要属性示例 2. Pandas 数据的导入与导出2.1 读取 CSV 文件2.2 读取 Excel 文件2.3 写入 CSV 文件2.4 读取 JSON 文件 3. Pandas 的数据操作3.1 数据选择和…

IPsec-Vpn

网络括谱图 IPSec-VPN 配置思路 1 配置IP地址 FWA:IP地址的配置 [FW1000-A]interface GigabitEthernet 1/0/0 [FW1000-A-GigabitEthernet1/0/0]ip address 10.1.1.1 24 [FW1000-A]interface GigabitEthernet 1/0/2 [FW1000-A-GigabitEthernet1/0/2]ip address

开源 AI 智能名片与 S2B2C 商城小程序:嫁接权威实现信任与增长

摘要&#xff1a;本文探讨了嫁接权威在产品营销中的重要性&#xff0c;并结合开源 AI 智能名片与 S2B2C 商城小程序&#xff0c;阐述了如何通过与权威关联来建立客户信任&#xff0c;提升产品竞争力。强调了在当今商业环境中&#xff0c;巧妙运用嫁接权威的方法&#xff0c;能够…

AI 智能名片链动 2+1 模式商城小程序中的体验策略

摘要&#xff1a;本文探讨了在 AI 智能名片链动 21 模式商城小程序中&#xff0c;体验策略如何服务于用户体验&#xff0c;以及与产品策略的区别。重点分析了该小程序如何通过关注用户在使用过程中的流畅度、视觉体感等方面&#xff0c;实现“让用户用得爽”的目标&#xff0c;…

JS中的事件和DOM操作

一、事件[重要] 1、 事件介绍 事件: 就是发生在浏览器(页面)上一件事,键盘事件,鼠标事件,表单事件,加载事件等等 2、 事件绑定方式 事件要想发生,就得将事件和标签先绑定(确定哪个标签发生什么事情,又有什么响应) 一个完整的事件有三部分 事件源(标签),哪里发出的事. 什么事(…

德勤校招网申笔试综合能力测试SHL题库与面试真题攻略

德勤的综合能力测试&#xff08;General Ability&#xff09;是其校园招聘在线测评的关键环节&#xff0c;旨在评估应聘者的多项认知能力。以下是对这部分内容的全面整合&#xff1a; 综合能力测试&#xff08;General Ability&#xff09; 测试时长为46分钟&#xff0c;包含…

Linux 文件权限详解与管理

文章目录 前言一、文件权限概述1. 权限表示格式2. 权限组合值 二、查看文件权限三、修改文件所有者与所属组1. 使用 chown 修改文件所有者2. 使用 chgrp 修改文件所属组3. 添加所有者 四、修改文件权限1. 符号方式2. 八进制方式3. 实际修改 总结 前言 在 Linux 系统中&#xf…

VS Code调整字体大小

##在工程目录底下.vscode/settings.json添加设置参数 {"editor.fontSize": 15,"window.zoomLevel": 1.5 }

MySQL—存储过程详解

基本介绍 存储过程和函数是数据库中预先编译并存储的一组SQL语句集合。它们的主要目的是提高代码的复用性、减少数据传输、简化业务逻辑处理&#xff0c;并且一旦编译成功&#xff0c;可以永久有效。 存储过程和函数的好处 提高代码的复用性&#xff1a;存储过程和函数可以在…

Redis6.0.9配置redis集群

写在前面 最近在完成暑期大作业&#xff0c;期间要将项目部署在云服务器上&#xff0c;其中需要进行缓存的配置&#xff0c;决定使用Redis&#xff0c;为了使系统更加健壮&#xff0c;选择配置Redis-Cluster。由于服务器资源有限&#xff0c;在一台服务器上运行6个Redis Instan…

docker desktop windows stop

服务docker改为启动 cmd下查看docker版本 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"registry-mirrors": ["https://hub.atomgit.com/"]…

三目运算判断字母大小写-C语言

1.问题&#xff1a; 输入一个字符&#xff0c;判别它是否为大写字母&#xff0c;如果是&#xff0c;将它转换成小写&#xff0c;如果不是&#xff0c;不转换。然后输出最后得到的字符&#xff0c;要求使用三目运算符。 2.解答&#xff1a; 用条件表达式来处理&#xff0c;当字…

Go基础学习04-变量重声明;类型转换;类型断言;Unicode代码点;类型别名;潜在类型

目录 变量重声明 类型断言 类型转换 类型转换注意事项 Unicode代码点 类型别名、潜在类型 类型别名的意义 变量重声明 编写代码&#xff1a; package mainimport "fmt"var container []string{"Beijing", "Shanghai"}func main() {fmt.Pr…

快递物流短信API接口代码

官网&#xff1a;快递鸟 API参数 用户信息类 一.短信模版 1.接口说明 使用快递鸟短信功能时&#xff0c;预先设置好短信模板和对应的发送规则&#xff0c;快递鸟短信API将根据设置的好的模板和规则&#xff0c;进行短信的发送和反馈。 (1)仅支持Json格式。 (2)请求指令810…

数据结构-2.9.双链表

一.双链表与单链表的对比&#xff1a; 二.双链表的初始化(带头结点)&#xff1a; 1.图解&#xff1a; 2.代码演示&#xff1a; #include<stdio.h> #include<stdlib.h> ​ //定义双链表结构体 typedef struct DNode {int data;struct DNode *prior;//前驱指针即指…

软件测试基础面试题【最新-附带答案】

1、介绍一下你上一家公司的测试流程吧&#xff1f; 1、产品经理拿下项目 2、所有技术人员&#xff08;开发&#xff0c;测试&#xff0c;运维&#xff0c;UI&#xff09;召开需求分析会议 3、测试组内召开会议&#xff08;明确测试需求&#xff0c;分配人员任务&#xff09;…