leecode-LCR 017. 最小覆盖子串(golang版本)

leecode最小覆盖字串

leecode链接地址

给定两个字符串 s 和 t 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串,则返回空字符串 "" 。

如果 s 中存在多个符合条件的子字符串,返回任意一个。

题解

bash 复制代码
func minWindow(s string, t string) string {
m := make(map[uint8]int)
	for i := 0; i < len(t); i++ {
		m[t[i]]++
	}
	valid := len(m)
	left := 0
	res := s
	has := false
	for right := 0; right < len(s); right++ {
		if v, ok := m[s[right]]; ok {
			m[s[right]]--
			if v == 1 {
				valid--
			}
		}
		if valid == 0 {
			for right-left >= len(t)-1 {
				has = true
				if v, ok := m[s[left]]; ok {
					if v == 0 {
						if right-left < len(res) {
							res = s[left : right+1]
						}
						break
					}
					m[s[left]]++
				}
				left++
			}
		}
	}
	if !has {
		return ""
	}
	return res
}

核心点一: 滑动窗口

我们分析一下题目,需要判断s 中包含 t 的所有字符的最短子字符串,说明需要在字符串s中寻找一个连续的区间,这个区间包含的字符需要囊括的字符串t中的全部字符。一般这种寻找连续区间的题目,我们第一反应就应该是使用双指针的滑动窗口来处理

我们现在以s=ADOBECODEBANC,t=ABC为例,逐步分析滑动窗口的过程

区间范围 是否包含字符串t
[0,0) 否
[0,1) 否
[0,2) 否
[0,4) 否
[0,5) 否
[0,6) 是

当前的滑动窗口包含的字符串是ADOBEC,这时已经完全包含字符串t的字符了。此时的滑动窗口指针分别是0,6,题目要求最短子字符串,这就意味着我们的工作还不能结束。相比于字符串t而言,此刻的滑动窗口内的字符数量远远大于t,这说明滑动窗口可能还有继续优化的空间。当右边的指针移动到完全包含字符串t时,左边的指针还有机会可以收缩窗口的空间。左边指针对应的字符是A,此刻滑动窗口内的字符A的数量为1,假如移动滑动窗口左边界,会使得窗口内不能完全包含t的字符,所以还是只能移动滑动窗口右边界。只有当滑动窗口内多加入一个A字符时,左侧边界就可以放弃A字符,却又不会影响整个滑动窗口能够包含t中的元素。

区间范围 是否包含字符串t 是否可以移动左边界
[0,7) 是 否
[0,8) 是 否
[0,9) 是 否
[0,10) 是 否
[0,11) 是 是
对于当前[0,11)包含的字符串,似乎不是最优的滑动窗口,因为左侧的A可以舍弃却不会影响最终的包含关系。
区间范围 是否包含字符串t 是否可以移动左边界
[1,11) 是 是
[2,11) 是 是
[3,11) 是 否
[4,11) 是 否
[5,11) 是 否
我们的滑动窗口还没有探索完毕整个字符串,我们再次移动右边界,探索滑动窗口的可能性。
区间范围 是否包含字符串t 是否可以移动左边界
-- -- --
[5,12) 是 否
[5,13) 是 是
[6,13) 是 是
[7,13) 是 是
[8,13) 是 是
[9,13) 是 否
此时,我们可以把上面所有包含t的时间窗口的字符串进行统计,找出最小的字符串,就是题解。

核心点二: 比较两个字串全排列是否相等

在这个题目中, 需要判断s 中包含 t 的所有字符的最短子字符串,可以首先思考一点,怎么比较两个字符串是相等的,也就是上面一个步骤中比较滑动窗口是否包含t。这里的相等不是一摸一样,而是包含相同的字符,如下所示的两个字符串就是一个全排列相等的字符串,因为他们包含了相同的字符:

bash 复制代码
字符串abcd: a 1个  b 1个 c 1个 d 1个
字符串dcba:  a 1个  b 1个 c 1个 d 1个

我们来思考一下应该怎么写一个函数来判断这两个字符是否相等。我的第一想法是构建一个两个map结构的计数器,分别统计两个字符串的字符数量,计数器以字母为key值,以字母在字符串中的数量为value值,然后比较两个map是否一致。如果写出来大概是这么一段代码。

bash 复制代码
func equalString(a, b string) bool {
	ma := counnter(a)
	mb := counnter(b)
	return equalMap(ma,mb)
	

}

func counnter(s string)map[uint8]int{
	ma := make(map[uint8]int)
	for i := 0; i < len(s); i++ {
		ma[s[i]]++
	}
	return ma
}

func equalMap(a,b map[uint8]int) bool{
	if a==nil||b==nil||
		len(a)!= len(b){
		return false
	}
	for k, v := range a {
		vv,ok:=b[k]
		if ok&&vv==v{
			continue
		}else {
			return false
		}
	}
	return true
}

有没有更简单的方案呢,很显然我们可以转换一下思路,我们来重新思考一下mb := counnter(b)。这个map也可以表示为:滑动窗口内还需要几个某种字符就可以完全涵盖字符串t中的字符了。

举个例子,

bash 复制代码
对于这么一个map,当前滑动窗口是[0,0),即窗口中没有任何字符:
a:1
b:2
c:3
我们可以这么理解,我们还需要1个a,2个b,3个c,才能完全涵盖字符串t
如果滑动窗口发生了变化[0,1),这时候我们在滑动窗口中新增了一个字符a,那么此时我们还需要个b,3个c,才能完全涵盖字符串t,但是这时我们可以发现,还需要2类有效字符的加入,对于滑动窗口而言是有效的。
假设map变成了

a:-2
b:-3
c:1
此时,很显然只需要一类有效字符了,这时候我们在滑动窗口中新增了一个字符c,那么我们可以刻得到
a:-2
b:-3
c:0,很显然这个滑动窗口已经满足需求了。

综上所述,使用一个有效字段数量,和一个map就可以统计滑动窗口是否完全包含某一个字符串。

相关推荐
朝朝辞暮i1 小时前
C++ 第 23 课:class —— 开始真正进入面向对象
开发语言·c++·算法
明月_清风2 小时前
Muse 登顶 App Store 第一,SDK 直接开源:AI Agent 开始进入下一个阶段
人工智能·后端
小师兄吃牛肉2 小时前
C语言篇:宏
c语言·开发语言
郑同学的笔记2 小时前
【c++随笔28】strcmp 和 memcmp对比
开发语言·c++
言乐63 小时前
Python根据无法识别搜索词找出可能输入内容模型
开发语言·python·django·virtualenv·pygame
weixin_307779133 小时前
有限产能智能排产与动态重排智能体:从需求解构到技术实现
开发语言·人工智能·算法·架构
kakakahahahaha3 小时前
Windows C盘临时文件清理:%temp%、Windows Temp、Prefetch、Windows.old与hiberfil.sys处理指南
c语言·开发语言·windows
朝朝辞暮i3 小时前
C++ 第 27 课:智能指针 shared_ptr
开发语言·c++·算法
朝朝辞暮i4 小时前
C++ 第 29 课:回调函数 Callback
开发语言·c++·算法
笨笨饿4 小时前
140_AI新手村MCP与Skills是干嘛的
开发语言·人工智能·python·stm32·单片机·嵌入式硬件·物联网