中等
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
*思路
- 首先遍历目标串 t , 记录种类数missingType,和种类的对应个数 map
- 然后遍历 s ,移动 r 指针,利用-1来确定种类数和个数符合条件。
- 若missingType=0 , 说明子串符合条件,这个时候移动 l 指针,利用+1 来缩小范围。
- 若 l 指针的移动,导致子串缺少目标种类了,着继续移动 r 指针。以此循环
let s = "ADOBECODEBANC", t = "ABC"
var minWindow = function (s, t) {
let minLen = s.length + 1;
let start = s.length; // 结果子串的起始位置
let map = {}; // 存储目标字符和对应的缺失个数
let missingType = 0; // 当前缺失的字符种类数
for (const c of t) { // t为baac的话,map为{a:2,b:1,c:1}
if (!map[c]) {
missingType++; // 需要找齐的种类数 +1
map[c] = 1;
} else {
map[c]++;
}
}
let l = 0, r = 0; // 左右指针
for (; r < s.length; r++) { // 扩张窗口,超出s串就结束
let rightChar = s[r]; // 获取right指向的新字符
if (map[rightChar] !== undefined) map[rightChar]--; // 是目标字符,它的缺失个数-1
if (map[rightChar] == 0) missingType--; // 它的缺失个数新变为0,缺失的种类数就-1
console.log('R->', map, r, '个数' + missingType);
while (missingType == 0) { // 当前窗口包含所有字符
if (r - l + 1 < minLen) { // 每一次都符合条件,比较子串长度,保存最短的。
minLen = r - l + 1;
start = l;
}
console.log('完成', l, r);
let leftChar = s[l]; // 左指针要右移,左指针指向的字符要被丢弃
if (map[leftChar] !== undefined) map[leftChar]++; // 被舍弃的是目标字符,缺失个数+1
if (map[leftChar] > 0) missingType++; // 如果缺失个数新变为>0,缺失的种类+1
l++; // 左指针要右移 收缩窗口
console.log('L---', map, l, '个数' + missingType);
}
}
if (start == s.length) return "";
return s.substring(start, start + minLen); // 根据起点和minLen截取子串
};