题目
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
解析
- 新建对象obj记录t中每种字符串出现的次数,并记录t中的字符串种类数target
var obj = {
}
for(let c of t){
if(c in obj) obj[c]++
else obj[c] = 1
}
target = Object.keys(obj) //3
obj的结果为
obj = {
'A' : 1,
'B' : 1,
'C': 1
}
- left、right为满足要求的滑动窗口的左右边界
var left = -1,right = -1
- i、j是当前滑动窗口的左右边界,count为滑动窗口中已经满足t中的字符数。遍历s中的每一项,当s[i]的值是t中的字符,obj[s[i]]–。当obj[s[i]] == 0时表示i~j中s[i]需要出现的次数已经足够,count++。当count = target时,表示当前窗口已经满足s中出现t的条件
for(let i = 0, j = 0; j < s.length; j++){
//当前窗口新进来的值在obj中
if(s[j] in obj){
obj[s[i]]--
//s[i]出现的次数足够时,count++
if(obj[s[i]] == 0) count++
//当前窗口最左边的字符无用或者出现次数>需要次数,可丢弃
while(((s[i] in obj) && obj[s[i]] < 0) || (! s[i] in obj)){
if(s[i] in obj) obj[s[i++]]++
else i++
}
//当前窗口已经出现t中所有字符
if(count == target){
//记录最短的满足要求的滑动窗口
if(left == -1 && right == -1 || right - left + 1 > j - i + 1){
left = i
right = j
}
}
}
代码
/**
* @param {string} s
* @param {string} t
* @return {string}
*/
var minWindow = function(s, t) {
//记录t中每个字符需要出现的次数
let obj = {
};
for(let c of t){
if(c in obj){
obj[c]++;
}else{
obj[c] = 1;
}
}
//滑动窗口的左右边界
var left = -1,right = -1;
//count为滑动窗口中出现t中字符的种类数
var count = 0,target = Object.keys(obj).length;
for(let i = 0, j = 0 ; j < s.length; j++){
// console.log('s[j]='+s[j]);
//新进来的值是t中的值j
if(s[j] in obj){
obj[s[j]]--;
// console.log('obj[s[j]]='+obj[s[j]]);
//滑动窗口中s[i]出现的次数已经足够
if(obj[s[j]] == 0) count++;
while((s[i] in obj) && obj[s[i]] < 0 || !(s[i] in obj)) {
// console.log('s[i]='+s[i]);
// console.log('obj[s[i]]='+obj[s[i]]);
//滑动窗口左移一位
if(s[i] in obj) obj[s[i++]]++;
else i++;
}
//滑动窗口包含t中所有字符
if(count == target){
if(left == -1 && right == -1 || right - left + 1 > j - i + 1 ){
// console.log(i,j);
left = i;
right = j;
}
}
}
}
if(left == -1) return "";
return s.slice(left,right+1);
};