LeetCode - 76 最小覆盖子串

news2025/2/26 0:36:16

目录

题目来源

题目描述

示例

提示

题目解析

算法源码


题目来源

76. 最小覆盖子串 - 力扣(LeetCode)

题目描述

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

注意:

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

示例

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

提示

  • 1 <= s.length, t.length <= 10^5
  • s 和 t 由英文字母组成

题目解析

本题要求的最小覆盖子串的含义是:包含某些指定字符,且要求最短的子串。

即题目要我们在s字符串中,找到一个子串,这个子串需要包含t字符串中所有字符,这样的子串有很多,我们需要其中最短的那个子串。

本题最容易想到的解法是滑动窗口,滑动窗口运动逻辑如下:

需要注意的是这里的滑动窗口是不定长的滑动窗口。

 

 

 

 

 

 以上就是变长滑动窗口的运动逻辑。

我们可以总结如下:

滑动窗口的范围即:左右指针的范围,初始时左右指针都指向索引0位置,

  • 如果滑动窗口内部没有包含了t中所有字母,则右指针向右移动一格,然后继续判断滑动窗口内部是否包含了t中所有字母。
  • 如果滑动窗口内部包含了t中所有字母,(此时滑动窗口就是一个满足要求的子串,我们将他记录下来),则左指针向右移动一格,然后继续判断滑动窗口内部是否包含了t中所有字母。

按照上面逻辑,我们可以将记录的子串比较长度,保留最短的作为题解。

通过上面总结,我们似乎发现逻辑并不复杂,我们可以按照上面逻辑实现一下:

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function (s, t) {
    if(s.length < t.length) return ''

    let l = 0
    let r = 0

    const ans = []

    while(r < s.length) {
        const subStr = s.substring(l,r+1)
        if(contain(subStr, t)) {
            ans.push(subStr)
            l++
        } else {
            r++
        }
    }

    if(!ans.length) return ''

    return ans.sort((a,b) => a.length - b.length)[0]
};

function contain(str, subStr) {
    const sup = {}
    for(let c of str) {
        sup[c] ? sup[c]++ : (sup[c]=1)
    }

    const sub = {}
    for(let c of subStr) {
        sub[c] ? sub[c]++ : (sub[c]=1)
    }

    let flag = true
    for(let c in sub) {
        if(!sup[c] || sub[c] > sup[c]) {
            flag = false
            break
        }
    }

    return flag
}

 但是结果却是超时,原因是我们算法的时间复杂度达到了O(n^2),而数量级1 <= s.length, t.length <= 10^5,最终会有10^10次循环,这是肯定超时的。

我们可以看下上面的代码,找找那部分是可以优化的?

答案是contain函数,这个函数的作用是验证滑动窗口内部是否包含t字符串中所有字符的,但是方法比较笨,每当滑动窗口位置改变,就会重新统计字符数量,然后比较。这其中必然存在大量重复统计工作。

利用滑动窗口解决问题,我们一定要学会差集思想,因为滑动窗口的移动是有规律的,比如每次向右移动一格,这样本轮滑动窗口状态和上一轮滑动窗口状态,必然存在交集区域,如下图BC就是两次滑动窗口的交集区域

 交集区域我们是不需要关注的,只需关注差集区域,如上图A和D,本轮滑动窗口,相当于在上一轮滑动窗口的基础上,删除了一格A,增加了一格D,这样的话,统计本轮滑动窗口内容,就不需要O(n)时间,只需要O(1)时间了。

对于本题,滑动窗口的运动规律要复杂一点,并字符数量统计也不简单。

首先,我们需要统计字符串t中各字符的数量,比如t="ABC",则统计结果为count: {A:1, B:1, C:1},并记录总数量为len = t.length。

然后开始滑动窗口运动:

滑动窗口运动中新增的字符c(即右指针向右移动一格后新增的内容),如果在t中,即count[c]存在,则count[c]--,那么此时len要不要也自减呢?

我们看两种情况:

用例1:

s = "ADOBECODEBANC", t = "ABC"

情况1:

 此时右指针指向的字符A,在t中存在,因此count[c]--,count: {A:0, B:1, C:1},此时应该len--,即len变为2。

情况2:

 此时右指针指向的字符“B”,在t中存在,因此count[c]--,count: {A:1, B:-1, C:0},此时滑动窗口内部含有了两个B,但是这并不能意味着需要len也减去1,对于len来说,最多只能减去统计到B个数,如果B个数超出统计个数,即count[B] < 0,此时len不应该自减。

上面是右指针运动中的特殊情况处理,对应的还有左指针运动逻辑处理:

左指针运动,必然是找到了符合要求的子串,即滑动窗口内部含有了所有t字符,此时左指针右移一格,如上图,此时失去了A,而A刚好是t字符串内的字符,即count[A]存在,此时应该count[A]++,即将count:{A:0, B:0, C:0} 变为 count:{A:1, B:0, C:0},而此时也应该len++。

 

但是对于

此时情况是,上面的滑窗的count: {A:0, B:-1, c:0}

当上面滑窗左指针右移一格后,变为下面的滑窗时,失去了B,刚好时t中字符,因此count[B]++,

此时 count: {A:0, B:0, c:0},那么此时len是否也要自增1呢?答案是不需要,因为失去的B是超出统计个数的,因此失去了不需要作任何处理。

算法源码

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function (s, t) {
  let len = t.length;

  const count = {};
  for (let c of t) {
    count[c] ? count[c]++ : (count[c] = 1);
  }

  let i = 0;
  let j = 0;
  let minLen = s.length + 1; // 最短子串的长度
  let start = 0; // 最短子串的起始位置

  while (j < s.length) {
    const jc = s[j];

    if (count[jc]-- > 0) { // 注意:这里count[c]--必须写在if条件中,因为count[jc]可以是负数,但是len不能是负数
      len--;
    }

    while (len === 0) {
      if (minLen > j - i + 1) {
        minLen = j - i + 1;
        start = i;
      }

      const ic = s[i];
      if (count[ic]++ >= 0) { // 注意:这里count[c]++必须写在if条件中,因为len只有在count[c]大于等于0时才能增加
        len++;
      }
      i++;
    }

    j++;
  }

  return minLen < s.length + 1 ? s.substring(start, start + minLen) : "";
};

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

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

相关文章

基于java+springboot+mybatis+vue+elementui的会议管理系统

项目介绍 随着社会竞争压力的不断加强 &#xff0c;企事业单位内部的会议都在不断的增加&#xff0c;有效的会议可以提高企事业内部的沟通&#xff0c;更好的做出符合战略目标的决策。但是当下会议的交接工作一直是通过人们口头传达的方式来进行的&#xff0c;很明显这种方式比…

NLP文章和视频违规声明原创案例集锦

一、 文章违规声明原创案例集锦 平台鼓励用户就自行创作并发布的作品标识原创,但作品本身应符合以下前提: 1、受著作权法保护(如公开性质内容不具备著作权,则不在原创范围内) 2、不得侵犯他人权益(如未经授权使用他人内容,则不在原创范围内) 3、符合平台运营规范(…

C++利器STL——vector详解

要努力&#xff0c;但不要着急&#xff0c;繁花锦簇&#xff0c;硕果累累都需要过程&#xff01; 目录 1.vector的介绍及使用 1.1vector的介绍 1.2vector的使用 2.vector模拟实现 3.vector常见试题 1.vector的介绍及使用 1.1vector的介绍 1. vector是表示可变大小数组的序列容…

从查询语句执行流程看MySQL架构

言 常言道&#xff0c;看待一个事情要先知全貌&#xff0c;从高维度认识、理解&#xff0c;然后再深入各个细节&#xff0c;一一击破。MySQL的学习也不例外&#xff0c;那么你知道一条SQL在MySQL中执行要经历哪些步骤吗&#xff1f;每个步骤都有MySQL的哪些“零件”参与吗&…

双十二薅羊毛!这几款数码好物不可错过

双十二即将开始&#xff0c;在这段时间里有的人已经将自己心仪的塞满了整个购物车了吧&#xff0c;而有的人还没想好到底要入手什么&#xff0c;如果你也是还在纠结的话&#xff0c;不知道该买什么又或是想知道哪些产品更适合你入手&#xff0c;不妨来看看小编今天为你带来的这…

【JavaScript函数】

JavaScript函数1 本节目标2 函数的概念3 函数的使用3.1 声明函数3.2 调用函数3.3 函数的封装4 函数的参数4.1 形参和实参4.2 执行过程4.3 注意点4.4 函数形参和实参个数不匹配问题5 函数的返回值5.1 return语句5.2 函数返回值注意事项5.3 break,continue,return的区别6 argumen…

Python 中的安全密码处理

前言 几乎每个应用程序都需要某种形式的身份验证、密码处理或使用安全凭据&#xff0c;例如 API 密钥。您可能不是安全专家&#xff0c;但您应该知道如何安全地处理所有这些密码和凭据&#xff0c;以保护应用程序用户的凭据和数据以及您自己的 API 密钥和各种令牌。 &#xf…

GitHub 最全的开发资源汇总系列

GitHub 最全的开发资源汇总系列 了解学习开发各种项目&#xff01;&#xff01;&#xff01; GitHub 最全的开发资源汇总系列 由伯乐在线持续更新 Java 资源大全&#xff1b;Java资源大全中文版&#xff0c;包括开发库、开发工具、网站、博客、微信、微博等。 —— Java资源…

建筑结构抗震分析之施加地震波的方法与理论机理

一、地震波的输入有三种方式&#xff1a; 第一种是是质量加速度施加法&#xff0c;通过达朗贝尔原理&#xff0c;将地震作用转化为施加在质点上惯性力&#xff1b;第二种是底部位移法&#xff0c;在结构底部直接输入位移地震波&#xff0c;模拟地面震动反应&#xff0c;计算结…

Function 源码解析与实践

作者&#xff1a;陈昌浩 1 导读 if…else…在代码中经常使用&#xff0c;听说可以通过 Java 8 的 Function 接口来消灭 if…else…&#xff01;Function 接口是什么&#xff1f;如果通过 Function 接口接口消灭 if…else…呢&#xff1f;让我们一起来探索一下吧。 2 Functio…

共享新机遇 共谋新发展 | 蓝海创意云携元宇宙技术参展2022昆明南博会

11月19日&#xff0c;第6届中国-南亚博览会暨第26届中国昆明进出口商品交易会&#xff08;以下简称南博会&#xff09;在昆明盛大开幕&#xff0c;经过10年的精心打造&#xff0c;南博会已经成为集国际贸易、投资洽谈、文化交流等为一体的高水平综合性国际博览会。 蓝海创意云…

草料二维码表单如何推送至工作群

在我们使用草料二维码进行隐患排查、故障报修、预约报名、巡检异常等场景时&#xff0c;需要时不时查看草料后台&#xff0c;检查是否有新的信息更新&#xff0c;或者提交后人工再单独通知一次&#xff0c;经常造成信息传递不及时&#xff0c;那么能不能当有表单提交时&#xf…

项目管理软件有哪些,哪个好用?

做过项目的朋友肯定都知道&#xff0c;项目管理软件是专门用来帮助计划和控制项目资源、成本与进度的计算机应用程序。这类软件可以帮助企业管理项目进度&#xff0c;节省项目人力成本支出&#xff0c;增进团队协作与沟通&#xff0c;提升团队成员工作效率&#xff0c;让资源可…

Java本地高性能缓存实践

Java缓存技术可分为远端缓存和本地缓存&#xff0c;远端缓存常用的方案有著名的redis和memcache&#xff0c;而本地缓存的代表技术主要有HashMap&#xff0c;Guava Cache&#xff0c;Caffeine和Encahche。远端缓存将在后面的博文中进行深入探讨&#xff0c;此处挖个坑&#xff…

【013】基于Vue的酒店客房管理系统(含管理员、普通用户两种身份(附源码数据库、课设报告)

这里写目录标题一、系统详细介绍二、系统部分设计思路三、项目获取一、系统详细介绍 前言&#xff1a; 这次带来的是基于NodejsVueMysql的酒店客房管理系统&#xff0c;含非常非常详细的课设报告&#xff0c;觉得物超所值&#xff01;文末附源码数据库、论文百度云链接 系统登…

高空简易水果采摘装置设计(CAD+proe)

目 录 摘 要 I Abstract II 1 绪论 1 1.1 选题背景及意义 1 1.2研究现状 1 1.2.1国外果园采摘机械现状 1 1.2.2国内果园采摘机械现状 4 1.2.3果园机械存在问题 5 1.2.4果园采摘机械的发展趋势 6 1.3研究主要内容 7 2 高空简易水果采摘装置原理 8 2.1 水果实采摘方式的选择 8 2.…

零基础入门JavaWeb——HTML相关知识

一、HTML概念 HTML是Hyper Text Markup Language的缩写。意思是超文本标记语言。它的作用是搭建网页结构&#xff0c;在网页上展示内容。 1.1 超文本 HTML文件本质上是文本文件&#xff0c;而普通的文本文件只能显示字符。但是HTML技术通过HTML标签把其他网页、图片、音频、…

微信公众号留言如何实时提醒

几乎每个官方品牌都有一个微信公众号&#xff0c;并且会不定期发布和品牌、产品相关的内容&#xff0c;也经常会收到一些用户的留言。但并不是运营人员每时每刻都登录在公众号后台&#xff0c;查看并回复这些用户的问题&#xff0c;如果我希望有用户给我们公众号留言后&#xf…

运动酒店,如何“奇袭”文旅产业精准蓝海赛道——缤跃酒店

近日&#xff0c;缤跃酒店战略牵手昌泰高速&#xff0c;进驻雷公坳文体产业园&#xff0c;共建江西大健康产业重点基地。作为锦江酒店(中国区)旗下360度健康运动中高端生活方式品牌&#xff0c;缤跃高调与南昌雷公坳文体产业园达成战略合作&#xff0c;强势入驻体育产业园&…

Python读取复杂电子表格(CSV)数据小技巧一则

关于CSV格式 逗号分隔值&#xff08;Comma-Separated Values&#xff0c;CSV&#xff0c;有时也称为字符分隔值&#xff0c;因为分隔字符也可以不是逗号&#xff09;&#xff0c;其文件以纯文本形式存储表格数据&#xff08;数字和文本&#xff09;。“CSV”并不是一种单一的、…