最小覆盖子串(LeetCode 76)

1.问题描述

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

2.难度等级

Hard。

3.热门指数

★★★★☆

4.解题思路

问题要求返回字符串 s 中包含字符串 t 的全部字符的最小字串。我们可以将最小子串看成一个窗口,我们称包含 t 全部字母的窗口为「可行窗口」。

所以我们可以尝试用滑动窗口的思想解决这个问题。

在滑动窗口类型的问题中都会有两个指针,一个用于「延伸」现有窗口的 r 指针,和一个用于「收缩」窗口的 l 指针。在任意时刻,只有一个指针运动,而另一个保持静止。我们在 s 上滑动窗口,通过移动 r 指针不断扩张窗口。当窗口包含 t 全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。
在这里插入图片描述
如何判断当前的窗口包含所有 t 所需的字符呢?我们可以用一个哈希表表示 t 中所有的字符以及它们的个数,用一个哈希表动态维护窗口中所有的字符以及它们的个数,如果这个动态表中包含 t 的哈希表中的所有字符,并且对应的个数都不小于 t 的哈希表中各个字符的个数,那么当前的窗口是「可行」的。

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

时间复杂度: 最坏情况下左右指针对 s 的每个元素各遍历一遍,哈希表中对 s 中的每个元素各插入、删除一次。对 t 中的元素各插入一次。左右指针每次移动都要检查窗口是否「可行」,每次检查是否可行会遍历整个 t 的哈希表。哈希表的大小与字符集的大小有关,设字符集大小为 C,则时间复杂度为O(Cm+n),其中 m 为 s 长度,n 为 t 长度。

空间复杂度: 这里用了两张哈希表作为辅助空间,每张哈希表最多不会存放超过字符集大小的键值对,我们设字符集大小为 C ,则渐进空间复杂度为O(C)

下面以 Golang 为例给出实现。

func minWindow(s string, t string) string {
   
	mt := make(map[rune]int)
	for _, c := range t {
   
		mt[c]++
	}

	var minl, minr int      // 最小窗口左右下标
	var winlen int          // 最小窗口长度
	var l, r int            // 滑动窗口左右下标
	m := make(map[rune]int) // 窗口内字符数
	for ; r < len(s); r++ {
   
		m[rune(s[r])]++
		if !cover(m, mt) {
   
			continue
		}
		for ; l <= r; l++ {
   
			m[rune(s[l])]--
			if !cover(m, mt) {
   
				if winlen == 0 || r-l+1 < winlen {
   
					minl, minr = l, r
					winlen = r - l + 1
				}
				// 当前元素被删除,所以滑动窗口起始下标要移到下一位
				l++
				break
			}
		}
	}
	if winlen > 0 {
   
		return s[minl : minr+1]
	}
	return ""
}

func cover(m, mt map[rune]int) bool {
   
	for k, v := range mt {
   
		if m[k] < v {
   
			return false
		}
	}
	return true
}

参考文献

76. 最小覆盖子串 - LeetCode

相关推荐

  1. leetcode 76. 覆盖

    2023-12-27 07:28:02       43 阅读
  2. LeetCode -- 76. 覆盖

    2023-12-27 07:28:02       19 阅读
  3. LeetCode 76 覆盖

    2023-12-27 07:28:02       19 阅读
  4. Leetcode 76. 覆盖

    2023-12-27 07:28:02       10 阅读
  5. LeetCode 76. 覆盖 滑动窗口框架

    2023-12-27 07:28:02       43 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-27 07:28:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-27 07:28:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-27 07:28:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-27 07:28:02       20 阅读

热门阅读

  1. Unity编辑器紫色

    2023-12-27 07:28:02       35 阅读
  2. mysql如何分析sql是否成功使用索引

    2023-12-27 07:28:02       43 阅读
  3. 专属于程序员烂漫的表白||Python画动态爱心

    2023-12-27 07:28:02       43 阅读
  4. 微信小程序:跳转页面

    2023-12-27 07:28:02       43 阅读
  5. 运算符讲解

    2023-12-27 07:28:02       32 阅读
  6. 微信小程序实现一个天气预报应用程序

    2023-12-27 07:28:02       43 阅读
  7. C语言:冒泡排序算法的原理

    2023-12-27 07:28:02       27 阅读
  8. 【VS】如何把wpf项目打包成exe文件

    2023-12-27 07:28:02       29 阅读
  9. 数据库的连接池详解

    2023-12-27 07:28:02       32 阅读
  10. 单元测试实战

    2023-12-27 07:28:02       46 阅读
  11. WPF RelativeSource

    2023-12-27 07:28:02       40 阅读
  12. 10分钟了解nextTick,并实现简易版本的nextTick

    2023-12-27 07:28:02       33 阅读
  13. 【Python】FastAPI学习记录(二)

    2023-12-27 07:28:02       44 阅读