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

news2024/9/24 11:44:58

目录

题目链接: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)){
                // 如果当前窗口没有包含的话就添加元素,并右移right
                mapS.put(s.charAt(right), mapS.getOrDefault(s.charAt(right),0) + 1);
                right++;

            }else {
                // 如果当前窗口包含了的话,判断并更新结果的起始位置和长度
                if (resLen > (right - left)){
                    resStart = left;
                    resLen = right - left;
                }

                // 就删除元素,并右移left
                mapS.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.coloradmin.cn/o/2160255.html

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

相关文章

[Python学习日记-29] 开发基础练习2——三级菜单与用户登录

[Python学习日记-29] 开发基础练习2——三级菜单与用户登录 简介 三级菜单 用户登录 简介 该练习使用了列表、字典、字符串等之前学到的数据类型&#xff0c;用于巩固实践之前学习的内容。 三级菜单 一、题目 数据结构&#xff1a; menu { 北京: { 海淀: { …

纯css实现选项卡

<span class"flex tab" ><view :class"tabStyle(1)" click"tabClick(1)">变形监测</view><view :class"tabStyle(2)" click"tabClick(2)">渗流渗压</view></span>tabIndex:1tabClick…

src漏洞挖掘 | 记某学校网站的一次漏洞挖掘

&#x1f497;想加内部圈子&#xff0c;请联系我&#xff01; &#x1f497;文章交流&#xff0c;请联系我&#xff01;&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领…

【附实例】Python字典的各种操作

一、字典理解 Python 字典是一种可变容器模型&#xff0c;且可存储任意类型对象。字典的每个键值对用冒号 : 分割&#xff0c;每对之间用逗号 , 分割&#xff0c;整个字典包括在花括号 {} 中。 二、访问字典 ①.访问键名 my_dict {name: Alice, age: 30, city: New York} k…

显示数量以及坐标区间

import re import numpy as np import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties# 动态加载字体文件 font_path /usr/local/sunlogin/res/font/wqy-zenhei.ttc # 替换为实际字体路径 my_font FontProperties(fnamefont_path)# 定义日志…

【折腾笔记】雷池WAF+FRP+Nginx实现安全可靠的内网穿透

前言 在网上看了许多关于WAFFRPNginx的方式来保护内网穿透的Web服务&#xff0c;但是在网上搜寻的结果都是将WAF部署在了源站上面&#xff0c;由于我的Web服务都是部署在NAS上面&#xff0c;然后使用Frp来穿透访问的&#xff0c;我认为WAF应该部署在服务器上面比较合适&#x…

基于STM32F103C8T6单片机的农业环境监测系统设计

本设计是基于STM32F103C8T6单片机的农业环境监测系统&#xff0c;能够完成对作物的生长环境进行信息监测和异常报警&#xff0c;并通过手机APP来实现查看信息和设定阈值的功能。为了实现设计的功能&#xff0c;该系统应该有以下模块&#xff1a;包括STM32单片机模块、水环境PH值…

css禁止图片保存,CSS中的图片保存方法

“css中的图片”指的就是镶在CSS样式表中的图片。在我们用在浏览器保存网页时&#xff0c;很多时候&#xff0c;下载网页里的图片都下载不到&#xff0c;这样的话就会使网页非常不美观。所以&#xff0c;今天小编就给大家介绍集中保存方法。 以下是几种保存方法。 (一)使用网…

Unity 设计模式 之 行为型模式 -【中介者模式】【迭代器模式】【解释器模式】

Unity 设计模式 之 行为型模式 -【中介者模式】【迭代器模式】【解释器模式】 目录 Unity 设计模式 之 行为型模式 -【中介者模式】【迭代器模式】【解释器模式】 一、简单介绍 二、中介者模式&#xff08;Mediator Pattern&#xff09; 1、什么时候使用中介者模式 2、使用…

java项目之基于springboot的医院资源管理系统源码

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的医院资源管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风…

计算存款利息-C语言

1.问题&#xff1a; 假设有本金1000元&#xff0c;想存一年&#xff0c;有三种方法可选择&#xff1a; A活期&#xff0c;年利率为0.0036&#xff1b; B一年期定期&#xff0c;年利率为0.0225&#xff1b; C存两次半年定期&#xff0c;年利率为0.0198。 请分别计算出一年后…

Ubuntu的基本用法与指令(为后面学习ROS打基础)

目录 0.声明&#xff1a;此博客的部分内容来自B站up主 机器人工匠阿杰&#xff0c;欢迎大家前往up主视频区学习&#xff08;本人正在跟随此up主的视频学习无人机的部分相关知识&#xff09; 1.win空格&#xff08;切换中英文&#xff09; 2.终端指令 1.ls&#xff1a;显示主…

ATTCK实战系列-Vulnstack三层网络域渗透靶场(一)

ATT&CK实战系列-Vulnstack三层网络域渗透靶场&#xff08;一&#xff09; 一、环境搭建1.1 靶场拓扑图1.2 靶场下载链接1.3 虚拟机配置1.3.1 Windows 7 (web服务器)1.3.2 Windows 2008 (域控)1.3.3 Win2k3 (域内主机) 二、外网打点突破2.1 信息搜集2.2 phpmyadmin 后台 Get…

netfilter和iptables--netfilter源码篇

netfilter和iptables–netfilter源码篇 防火墙是保护服务器和基础设施的重要工具&#xff0c;在Linux系统下&#xff0c;目前广泛使用的防火墙工具是iptables&#xff0c;但实际进行规则实施并产生实际作用的是Netfilter&#xff0c;iptables与内核中的netfilter框架中Hook协同…

❤Node11-登录人token信息接口

❤Node11-登录人token信息接口​ 上一章我们已经从登录部分拿到了用户的登录jwt返回的token信息&#xff0c;接下来我们就通过token来换取用户信息 这里我们可以将其理解为一种加密以及解密的思想来思考这个jwt和token的关系&#xff0c;token就是一个加密的字符串&#xff0c…

【JavaEE】——内存可见性问题

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 一&#xff1a;内存可见性问题 1&#xff1a;代码解释 2&#xff1a;结果分析 &#xff08;1&#xf…

《现代畜牧兽医》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《现代畜牧兽医》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的第一批认定 学术期刊。 问&#xff1a;《现代畜牧兽医》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;辽宁省科学技术协会 …

vue2实现提取字符串数字并修改数字样式(正则表达式)

如果你要在循环中提取 item.companyName 中的数字&#xff0c;并且希望为这些数字改变颜色和边距&#xff0c;可以对每个 item 进行处理。此处是一个实现示例&#xff1a; <template> <div> <div class"box" v-for"(item, index) in coldBase…

学校气膜体育馆:低成本、高效率的灵活运动空间—轻空间

在当前教育设施的升级中&#xff0c;传统体育馆的建设往往面临长时间、高成本、以及繁琐的审批流程等诸多挑战。然而&#xff0c;学校无需再为这些问题烦恼&#xff0c;只需选择气膜结构的体育馆&#xff0c;就能快速、高效地解决体育场地需求。气膜体育馆凭借其灵活的设计和高…

Java项目实战II基于SSM的国外摇滚乐队交流和周边售卖系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着互联网技术的飞速发展&#xff0c;信息传播的广度和深度不断拓展&#xff0c;为各行业的创新发展…