当前位置: 首页 > news >正文

76. 最小覆盖子串。优化官方题解!

leetcode原题如下:

        

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

注意:

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

        

解题思路---滑动窗口

如何判断当前的窗口包含所有 t 所需的字符呢?我们可以用一个哈希表表示 t 中所有的字符以及它们的个数,用一个哈希表动态维护窗口中所有的字符以及它们的个数,如果这个动态表中包含 t 的哈希表中的所有字符,并且对应的个数都不小于 t 的哈希表中各个字符的个数,那么当前的窗口是「可行」的。

官方题解:

    Map<Character, Integer> ori = new HashMap<Character, Integer>();Map<Character, Integer> cnt = new HashMap<Character, Integer>();public String minWindow(String s, String t) {Map<Character, Integer> ori = new HashMap<>();Map<Character, Integer> cnt = new HashMap<>();// 预处理,初始化 ori 表for (int i = 0; i < t.length(); i++) {char c = t.charAt(i);ori.put(c, ori.getOrDefault(c, 0) + 1);}int l = 0, r = 0;int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;int sLen = s.length();int required = ori.size();  // 需要匹配的字符种类数量int formed = 0;  // 已经匹配的字符种类数量while (r < sLen) {char c = s.charAt(r);cnt.put(c, cnt.getOrDefault(c, 0) + 1);if (ori.containsKey(c) && cnt.get(c).equals(ori.get(c))) {formed++;}while (formed == required && l <= r) {if (r - l + 1 < len) {len = r - l + 1;ansL = l;ansR = l + len;}char leftChar = s.charAt(l);cnt.put(leftChar, cnt.get(leftChar) - 1);if (ori.containsKey(leftChar) && cnt.get(leftChar) < ori.get(leftChar)) {formed--;}l++;}r++;}return ansL == -1 ? "" : s.substring(ansL, ansR);}

注意:这里 t 中可能出现重复的字符,所以我们要记录字符的个数。

考虑如何优化? 如果 s=XX⋯XABCXXXX,t=ABC,那么显然 [XX⋯XABC]是第一个得到的「可行」区间,得到这个可行区间后,我们按照「收缩」窗口的原则更新左边界,得到最小区间。我们其实做了一些无用的操作,就是更新右边界的时候「延伸」进了很多无用的 X,更新左边界的时候「收缩」扔掉了这些无用的 X,做了这么多无用的操作,只是为了得到短短的 ABC。没错,其实在 s 中,有的字符我们是不关心的,我们只关心 t中出现的字符,我们可不可以先预处理 s,扔掉那些 t 中没有出现的字符,然后再做滑动窗口呢?也许你会说,这样可能出现 XXABXXC的情况,在统计长度的时候可以扔掉前两个 X,但是不扔掉中间的 X,怎样解决这个问题呢?优化后的时空复杂度又是多少?代码给出优化的版本.

public class MinimumWindowSubstring {public String minWindow(String s, String t) {// 用于记录 t 中各字符需要匹配的次数Map<Character, Integer> ori = new HashMap<>();// 用于记录当前窗口中各字符已匹配的次数Map<Character, Integer> cnt = new HashMap<>();// 预处理,初始化 ori 表for (int i = 0; i < t.length(); i++) {char c = t.charAt(i);ori.put(c, ori.getOrDefault(c, 0) + 1);}int l = 0, r = 0; // 窗口的左右边界int len = Integer.MAX_VALUE; // 记录当前最小窗口的长度int ansL = -1, ansR = -1; // 记录当前最小窗口的左右边界int sLen = s.length(); // 字符串 s 的长度int required = ori.size(); // 需要匹配的字符种类数量int formed = 0; // 已经匹配的字符种类数量// 右指针滑动while (r < sLen) {char c = s.charAt(r);cnt.put(c, cnt.getOrDefault(c, 0) + 1);// 如果当前字符在 ori 表中,并且已匹配次数等于 ori 表中的次数,增加已匹配字符种类数量if (ori.containsKey(c) && cnt.get(c).equals(ori.get(c))) {formed++;}// 左指针滑动,窗口收缩while (formed == required && l <= r) {// 更新最小窗口的长度和边界if (r - l + 1 < len) {len = r - l + 1;ansL = l;ansR = l + len;}// 移动左指针,减少已匹配字符的次数char leftChar = s.charAt(l);cnt.put(leftChar, cnt.get(leftChar) - 1);// 如果左边界字符在 ori 表中,并且减少后的次数小于 ori 表中的次数,减少已匹配字符种类数量if (ori.containsKey(leftChar) && cnt.get(leftChar) < ori.get(leftChar)) {formed--;}l++;}// 右指针继续滑动r++;}// 返回最小窗口对应的子串return ansL == -1 ? "" : s.substring(ansL, ansR);}
}

这段代码中的核心思想是使用滑动窗口来找到包含字符串 t 中所有字符的最小窗口。下面是代码中各部分的解释:

  1. oricnt 的初始化:

    • ori 表用于记录字符串 t 中各字符需要匹配的次数。
    • cnt 表用于记录当前窗口中各字符已匹配的次数。
  2. 预处理,初始化 ori 表:

    • 遍历字符串 t,将其中各字符及其需要匹配的次数记录在 ori 表中。
  3. 窗口的左右边界 lr

    • 使用两个指针 lr 来确定窗口。
  4. requiredformed

    • required 记录需要匹配的字符种类数量,即 ori 表的大小。
    • formed 记录已经匹配的字符种类数量,初始为 0。
  5. 右指针滑动(while (r < sLen)):

    • 不断移动右指针 r,直到窗口包含了字符串 s 中的所有字符。
  6. 左指针滑动,窗口收缩(while (formed == required && l <= r)):

    • 移动左指针 l,尝试缩小窗口的大小。
    • 更新最小窗口的长度和边界。
  7. 左右指针继续滑动,直至右指针到达字符串末尾:

相关文章:

76. 最小覆盖子串。优化官方题解!

leetcode原题如下&#xff1a; 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找的子字符串中该字符数量…...

在国产GPU寒武纪MLU上快速上手Pytorch使用指南

本文旨在帮助Pytorch使用者快速上手使用寒武纪MLU。以代码块为主&#xff0c;文字尽可能简洁&#xff0c;许多部分对标NVIDIA CUDA。不正确的地方请留言更正。本文不定期更新。 文章目录 前言Cambricon PyTorch的Python包torch_mlu导入将模型加载到MLU上model.to(mlu)定义损失函…...

重生奇迹MU觉醒战士攻略

剑士连招技巧&#xff1a;生命之光&#xff1a;PK前起手式&#xff0c;增加血上限。 雷霆裂闪&#xff1a;眩晕住对手&#xff0c;剑士PK战士第一技能&#xff0c;雷霆裂闪是否使用好关系到胜负。 霹雳回旋斩&#xff1a;雷霆裂闪后可以选择用霹雳回旋斩跑出一定范围(因为对手…...

美颜技术详解:深入了解视频美颜SDK的工作机制

本文将深入探讨视频美颜SDK的工作机制&#xff0c;揭示其背后的科技奥秘和算法原理。 1.引言 视频美颜SDK作为一种集成到应用程序中的技术工具&#xff0c;通过先进的算法和图像处理技术&#xff0c;为用户提供令人印象深刻的实时美颜效果。 2.视频美颜SDK的基本工作原理 首…...

3D模型格式转换工具如何实现高性能数据转换?请看CAE系统开发实例!

​ 客户背景 DP Technology是全球知名的CAM的供应商&#xff0c;在全球8个国家设有18个办事处。DP Technology提供的CAMESPRIT系统是一个用于数控编程&#xff0c;优化和仿真全方面的CAM系统。CAMESPRIT的客户来自多个行业&#xff0c;因此支持多种CAD工具和文件格式显得格外重…...

多级缓存:亿级流量的缓存方案

文章目录 一.多级缓存的引入二.JVM进程缓存三.Lua语法入门四.多级缓存1.OpenResty2.查询Tomcat3.Redis缓存预热4.查询Redis缓存5.Nginx本地缓存6.缓存同步 一.多级缓存的引入 传统缓存的问题 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未…...

C语言——高精度乘法

一、引子 高精度乘法相较于高精度加法和减法有更多的不同&#xff0c;加法和减法是一位对应一位进行操作的&#xff0c;而乘法是一个数的每一位对另一个数的每一位进行操作&#xff0c;需要的计算步骤更多。 二、核心算法 void Calculate(int num1[], int num2[], int numres…...

为什么C语言没有被C++所取代呢?

今日话题&#xff0c;为什么C语言没有被C所取代呢&#xff1f;虽然C是一个功能更强大的语言&#xff0c;但C语言在嵌入式领域仍然广泛使用&#xff0c;因为它更轻量级、更具可移植性&#xff0c;并且更适合在资源受限的环境中工作。这就是为什么C语言没有被C所取代的原因。如果…...

基于Spring的枚举类+策略模式设计(以实现多种第三方支付功能为例)

摘要 最近阅读《贯彻设计模式》这本书&#xff0c;里面使用一个更真实的项目来介绍设计模式的使用&#xff0c;相较于其它那些只会以披萨、厨师为例的设计模式书籍是有些进步。但这书有时候为了使用设计模式而强行朝着对应的 UML 图来设计类结构&#xff0c;并且对设计理念缺少…...

基于Linphone android sdk开发Android软话机

1.Linphone简介 1.1 简介 LinPhone是一个遵循GPL协议的开源网络电话或者IP语音电话&#xff08;VOIP&#xff09;系统&#xff0c;其主要如下。使用linphone&#xff0c;开发者可以在互联网上随意的通信&#xff0c;包括语音、视频、即时文本消息。linphone使用SIP协议&#…...

[论文分享]TimeDRL:多元时间序列的解纠缠表示学习

论文题目&#xff1a;TimeDRL: Disentangled Representation Learning for Multivariate Time-Series 论文地址&#xff1a;https://arxiv.org/abs/2312.04142 代码地址&#xff1a;暂无 关键要点&#xff1a;多元时间序列&#xff0c;自监督表征学习&#xff0c;分类和预测 摘…...

分享一个好看的vs主题

最近发现了一个很好看的vs主题&#xff08;个人认为挺好看的&#xff09;&#xff0c;想要分享给大家。 主题的名字叫NightOwl&#xff0c;和vscode的主题颜色挺像的。操作方法也十分简单&#xff0c;首先我们先在最上面哪一行找到扩展。 然后点击管理扩展&#xff0c;再搜索栏…...

什么是云呼叫中心?

云呼叫中心作为一种高效的企业呼叫管理方案&#xff0c;越来越受到企业的青睐&#xff0c;常被用于管理客服和销售业务。那么&#xff0c;云呼叫中心到底是什么&#xff1f; 什么是云呼叫中心&#xff1f; 云呼叫中心是一种基于互联网的呼叫管理系统&#xff0c;与传统的呼叫…...

还在用nvm?来试试更快的node版本管理工具——fnm

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热衷分享有趣实用的文章&#xff0c;希望大家多多支持&#xff0c;一起进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 什么是node版本管理 常见的node版本管理工具 fnm是什么 安装fnm …...

【Hadoop精讲】HDFS详解

目录 理论知识点 角色功能 元数据持久化 安全模式 SecondaryNameNode(SNN) 副本放置策略 HDFS写流程 HDFS读流程 HA高可用 CPA原则 Paxos算法 HA解决方案 HDFS-Fedration解决方案&#xff08;联邦机制&#xff09; 理论知识点 角色功能 元数据持久化 另一台机器就…...

企业需要哪些数字化管理系统?

企业需要哪些数字化管理系统&#xff1f; ✅企业引进管理系统肯定是为了帮助整合和管理大量的数据&#xff0c;从而优化业务流程&#xff0c;提高工作效率和生产力。 ❌但是&#xff0c;如果各个系统之间不互通、无法互相关联数据的话&#xff0c;反而会增加工作量和时间成本…...

【vue】开发常见问题及解决方案

有一些问题不限于 Vue&#xff0c;还适应于其他类型的 SPA 项目。 1. 页面权限控制和登陆验证页面权限控制 页面权限控制是什么意思呢&#xff1f; 就是一个网站有不同的角色&#xff0c;比如管理员和普通用户&#xff0c;要求不同的角色能访问的页面是不一样的。如果一个页…...

飞天使-k8s知识点3-卸载yum 安装的k8s

要彻底卸载使用yum安装的 Kubernetes 集群&#xff0c;您可以按照以下步骤进行操作&#xff1a; 停止 Kubernetes 服务&#xff1a; sudo systemctl stop kubelet sudo systemctl stop docker 卸载 Kubernetes 组件&#xff1a; sudo yum remove -y kubelet kubeadm kubectl…...

ZooKeeper 集群搭建

文章目录 ZooKeeper 概述选举机制搭建前准备分布式配置分布式安装解压缩并重命名配置环境配置服务器编号配置文件 操作集群编写脚本运行脚本搭建过程中常见错误 ZooKeeper 概述 Zookeeper 是一个开源的分布式服务协调框架&#xff0c;由Apache软件基金会开发和维护。以下是对Z…...

Meson:现代的构建系统

Meson是一款现代化、高性能的开源构建系统&#xff0c;旨在提供简单、快速和可读性强的构建脚本。Meson被设计为跨平台的&#xff0c;支持多种编程语言&#xff0c;包括C、C、Fortran、Python等。其目标是替代传统的构建工具&#xff0c;如Autotools和CMake&#xff0c;提供更简…...

OpenClaw实战案例:Qwen3.5-9B自动化处理电商客服问答

OpenClaw实战案例&#xff1a;Qwen3.5-9B自动化处理电商客服问答 1. 为什么选择OpenClaw处理电商客服问答 去年夏天&#xff0c;我开始经营一家小型手工艺品网店。随着订单量增长&#xff0c;每天要处理几十条客户咨询&#xff0c;从"我的订单到哪了"到"退货怎…...

go实战案例:如何在 Go-kit 和 Service Meh 中进行服务注册与发现?

今天分享的是如何在Go-kit和ServiceMesh中进行服务注册与发现的案例。在上文中&#xff0c;我们基于搭建好的 Consul 集群&#xff0c;通过 Consul 中提供的 HTTP API 实现了 register 的服务注册与发现功能。我们采用手动构造HTTP请求的方式&#xff0c;在服务启动时发送服务实…...

毕业设计实战:基于SpringBoot+Vue+MySQL的校园一卡通管理系统设计与实现指南

毕业设计实战&#xff1a;基于SpringBootVueMySQL的校园一卡通管理系统设计与实现指南 在开发“基于SpringBootVueMySQL的校园一卡通管理系统”毕业设计时&#xff0c;曾因器材借用表未通过学生ID与器材ID双外键关联踩过关键坑——初期仅单独设计借用表的编号字段&#xff0c;…...

Flow3D 11.1玩转金属3D打印模拟】手把手教你搞熔池仿真

Flow3d 11.1 lpbf 熔池仿真模拟 slm 选区激光熔化 降价 与别的店大几百上千的基本一致 (视频是多层模拟的视频) 1.该模拟设包含颗粒床以及建立过程&#xff08;有视频&#xff09;&#xff0c;运用Flow3D11.1、EDEM软件以及Gambit软件&#xff08;含安装包&#xff09;&am…...

运算放大器与电压比较器原理及应用对比

运算放大器与电压比较器的原理分析与工程应用1. 器件概述与符号对比1.1 基本符号结构运算放大器(Operational Amplifier)和电压比较器(Voltage Comparator)在原理图符号上具有完全相同的表现形式&#xff0c;均包含五个基本引脚&#xff1a;正电源引脚(VCC/V)负电源引脚(GND/-V…...

OpenClaw新手入门:Qwen3.5-9B镜像一键部署与基础配置

OpenClaw新手入门&#xff1a;Qwen3.5-9B镜像一键部署与基础配置 1. 为什么选择Qwen3.5-9B作为OpenClaw的"大脑"&#xff1f; 去年冬天&#xff0c;当我第一次尝试用OpenClaw自动化处理周报时&#xff0c;发现默认的小模型经常把"会议纪要"理解成"会…...

python-学生选课成绩系统vue

目录系统架构设计前端实现模块后端API设计数据库表结构关键技术点测试与部署扩展性考虑项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作系统架构设计 采用前后端分离架构&#xff1a; 前端&#xff1a;Vue 3 TypeScript Ele…...

ANSYS Workbench ACT插件 FE Info 实战指南:从安装调试到高效查询

1. 为什么你需要FE Info插件 在ANSYS Workbench中进行有限元分析时&#xff0c;经常会遇到需要查询节点编号、单元信息或者测量距离的情况。比如设置耦合约束时&#xff0c;需要精确知道两个节点的距离&#xff1b;验证网格质量时&#xff0c;需要快速定位特定单元&#xff1b;…...

镜头结构设计中的公差与成本平衡:如何避免过度设计

镜头结构设计中的公差与成本平衡&#xff1a;如何避免过度设计 在高端光学镜头的研发过程中&#xff0c;工程师们常常面临一个核心矛盾&#xff1a;如何在确保光学性能的同时&#xff0c;避免因过度追求精度而导致生产成本失控&#xff1f;这个看似简单的平衡问题&#xff0c;实…...

Gigasoft ProEssentials 使AI助手能够通过实时访问API图表配置并提供支持答案

利用人工智能访问改进图表开发Gigasoft ProEssentials 使 AI 助手能够通过实时访问 API 生成精确的图表配置并提供支持答案。Gigasoft ProEssentials 是一款功能强大的 Windows 开发图表库&#xff0c;提供丰富的 2D 和 3D 图表类型。该产品提供了一套用途广泛的组件&#xff0…...