Leetcode76 最小覆盖子串题解

本文介绍了LeetCode第76题《最小覆盖子串》的解题方法,包括如何判断子串是否覆盖目标字符串、滑动窗口的概念以及如何实现。通过维护字符差值和覆盖数量,动态调整窗口大小,找到覆盖目标字符串的最小子串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目网址:https://leetcode-cn.com/problems/minimum-window-substring/

题目分析

这道题目,明显之处在于,我们需要在字符串 s 中框出一个窗口,来判断这个窗口中的子串是否覆盖了 t,如下图所示。就是要判断黄色窗口内的子串,有没有覆盖字符串 t

在这里插入图片描述

由此一来,我们需要解决两个很重要的问题。一是如何判断黄色窗口子串有没有覆盖 t,二是如何得到滑动窗口。

如何判断是否覆盖

假设我们有两个字符串,分别为 s1 = "OBECOEB"(上图中的黄色区域)和 t = "ABC"。如何判断 s1 有没有覆盖 t 呢?

我们可以分别统计字符串 s1t 中各字符的个数,得到下图。我们可以看到,t 中有 1 个 A,而 s1 中没有,因此 s1 不能覆盖 t

在这里插入图片描述

再比如,有字符串 s2 = "BANC"t 包含的字符均在 s2 中出现,且 t 中各字符的数量,都小于等于 s2 中相应字符的数量。因此,s2 覆盖了 t

并且,我们只需要关注那些出现在 t 中的字符,可以忽视掉那些不出现在 t 中的字符。比如,s1 中的 EO,它没有出现在 t 中,我们可以忽略它。同时为了节省空间,我们实际上保存好 ts1 各字符个数的差值就好。

我们只关心出现在 t 中的字符,把 t 中这些字符的个数减去 s1 中相应字符的个数,结果如下图。字符 A 的结果是正数,说明还有一个 A 没有被覆盖,因此字符串 s1 未能覆盖 t
在这里插入图片描述

但是,窗口是在不断变化的。如果每次变化窗口,都需要重新计算窗口中各字符的数量,且都要与 t 中相应字符的数量做差,这样做是很低效的。但事实上并非如此。

假设我们已经有了一个滑动窗口,窗口左、右下标分别为 lr。我们可以观察到,无论是向右移动 l 还是 r,都是只有一个字符的改变。例如,把 l 向右移动一位,字符 O 减少一个。实际上,我们只要得到一个窗口的各字符数量与 t 的差值,就可以快速地得到下一个窗口与 t 各字符数量的差值。

再进一步。

现在我们可以得到 t 与各个窗口中字符的差值。这是不是意味着我们每得到一个窗口,都需要来看看差值中每个数都小于等于 0?

其实,我们可以使用空间换时间的方法,再用一个变量 cnt 来表示覆盖的数量。还是字符串 s1 = "OBECOEB"t = "ABC"s1 实际上只覆盖 tBC 两个字符,此时 cnt 等于 2,小于 t 的长度。很明显,s1 未能覆盖 t

而窗口 s2 = "BANC"cnt 为 3,恰好等于 t 的长度,因此 s2 覆盖了 t

到这里,我们已经解决了第一个问题,如何判断子串有没有覆盖。接下来解决第二个问题,如何得到滑动窗口。

滑动窗口

同样,我们用下标 lr 来表示区间 [l, r] 中的子串。当然,我们可以枚举,把所有可能的子串都枚举出来,但这没有必要。

我们让 lr 都从 0 出发,并且可以得到字符差值,如下图所示。

在这里插入图片描述

此时

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值