个人感觉:
核心是利用 map 建立一个被包含字符串的字典,并记录好这个被包含字符串中每个元素(键名)出现的次数(键值)。
移动指针遍历,利用 map 的 has 方法,如果遇到被包含字符串中的元素,字典中对应元素的键值做出相应的改变。
当字典中所有键名对应的键值都为 0 时,意味着字符串都被包含了,进行窗口的缩小。
坑:
移动右指针时:只有字典元素对应键值为 0 的时候 ,记录被包含字符串总个数才进行 -1
移动左指针时:只有字典元素对应键值为 1 的时候,记录被包含字符串总个数才进行 +1
var minWindow = function (s, t) {
// 把被涵盖的字符串转成字典,把每个元素的初始键值都设置为 1
// 转换成字典 可以利用 has 方法便捷的判断是否存在(被包含)
let map = new Map();
for (let i = 0; i < t.length; i++) {
map.set(t[i], map.has(t[i]) ? map.get(t[i]) + 1 : 1);
}
// 初始化左右指针
let left = 0;
let right = 0;
// 最终最小覆盖字串的结果
let res = '';
// 判定被覆盖字符串是否都被包含了
let sum = map.size;
while (right < s.length) {
if (map.has(s[right])) {
map.set(s[right], map.get(s[right]) - 1);
// 当字典中某个元素多次出现的时候,这个元素的键值是可以减成负数的
// 第一个坑:当字典中键值为 0 的时候 sum才进行--
if(map.get(s[right]) === 0) sum--;
}
while (sum === 0) {
let newRes = s.substring(left, right + 1);
if(!res || res.length > newRes.length) res = newRes;
if (map.has(s[left])) {
map.set(s[left], map.get(s[left]) + 1);
// 第二个坑:只有当字典中键值为 1 时 sum才进行++
// 因为之前字典中元素对应的键值是可能为负数的
if(map.get(s[left]) === 1) sum++;
}
left++;
}
right++;
}
return res;
};