题目
- 最小覆盖子串
题目描述
给你一个字符串s、一个字符串t;返回s中涵盖t所有字符的最小子串。
说明
如果s中不存在涵盖t所有字符的子串,则返回空字符串""。
如果s中存在这样的子串,我们保证它是唯一的答案。
题目概述
就是说要在s中找到包含t中全部字母的一个子串,且这个子串一定是所有可能子串中最短的。
案例
示例一
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例二
输入:s = "a", t = "a"
输出:"a"
思路
1、我们在字符串S中使用双指针中的左右指针技巧,初始化left = right = 0,把索引左闭右开区间 [left, right) 称为一个「窗口」。
2、我们先不断地增加right指针扩大窗口[left, right),直到窗口中的字符串符合要求(包含了T中的所有字符)。
3、此时,我们停止增加right,转而不断增加left指针缩小窗口[left, right),直到窗口中的字符串不再符合要求(不包含T中的所有字符了);同时,每次增加left,我们都要更新一轮结果。
4、重复第2和第3步,直到right到达字符串S的尽头。
代码
package leetcode
import "log"
// minWindow
// 最小覆盖子串
func minWindow(s string, t string) string {
// 初始化计数器,分别记录【窗口】中字符的出现次数和T中字符串出现次数
window := map[byte]int{}
need := map[byte]int{}
for i := 0; i < len(t); i++ {
cur := t[i]
need[cur]++
}
maxNum := 1<<31 - 1
// 初始化窗口的两端,区间[left, right)
left, right := 0, 0
// 表示窗口中满足need条件的字符个数
// 如果valid和len(need)的大小相同,则说明窗口已满足条件,已经完全覆盖了字符串t
valid := 0
// @TODO 记录最小覆盖子串的起始索引及长度,计算最终结果使用
start, length := 0, maxNum
log.Println(right, left, start, length)
// 结束条件:right到达s的尽头
for right < len(s) {
// 即将移入窗口的值
cur := s[right]
right++
// 进行窗口数据更新
// 首先校验是否在T串
if _, ok := need[cur]; ok {
window[cur]++
// 表示窗口中满足need条件的字符个数
if window[cur] == need[cur] {
valid++
}
}
// 判断窗口是否需要收缩:valid==len(need)代表当前窗口已经满足need
for valid == len(need) {
// 在这里更新最小覆盖子串:最终结果产生位置
if (right - left) < length {
start = left
length = right - left
}
// 将移出窗口的字符
delS := s[left]
left++
if _, ok := need[delS]; ok {
// 既要移除窗口的值,也要移除验证的值
if window[delS] == need[delS] {
valid--
}
window[delS]--
}
}
}
// 返回最小覆盖子串
if length == maxNum {
return ""
} else {
log.Println(start, length)
return s[start:start+length]
}
}
参考
来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/mi…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。