76-最小覆盖子串
题目描述
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入: s = "ADOBECODEBANC", t = "ABC"
输出: "BANC"
示例 2:
输入: s = "a", t = "a"
输出: "a"
示例 3:
输入: s = "a", t = "aa"
输出: ""
分析
利用滑动窗口,left不动,right向右移动,直至二者之间的子串满足要求,即包含t的所有字符。此时开始滑动窗口,right不动,如果left右移一步之后子串仍满足要求则进行右移,否则的话left右移一步之后开始移动right。直至right到达字符串s的末尾。
题解
/**
* @param {string} s
* @param {string} t
* @return {string}
*/
var minWindow = function(s, t) {
let need = {};
let needType = 0;
let start = s.length;
let minLen = s.length + 1;
for(let i=0; i<t.length; i++) {
if(need[t[i]]) {
need[t[i]] += 1;
} else {
need[t[i]] = 1;
needType++;
}
}
let l=r=0;
for(; r<s.length; r++) {
let newWord = s[r]; // 新字符
if(need[newWord] !== undefined) need[newWord]-- // 新字符在need中,那么可以减一
if(need[newWord] == 0) needType-- // 如果经过上一步之后该字符的需求数为0,那么说明该Type不需要了
while(needType==0) { // needType==0 即当前子串满足要求,接下来将左指针右移直到不满足题目要求,也就是 needType>0
if(r-l+1<minLen) { // 如果碰到更短的子串,更新返回量
start = l;
minLen = r-l+1;
}
let leftWord = s[l]; // 旧字符
if(need[leftWord] !== undefined) need[leftWord]++ // 丢弃了need中的字符
if(need[leftWord] > 0) needType++ // 缺失种类加一
l++;
}
}
if(start==s.length) return ''
return s.substring(start, start+minLen);
};
分析
时间复杂度:O(n)
空间复杂度:O(k) 两个字符串的长度
难点
双指针,滑动窗口