题目
- 先记录 str2 的所有元素的词频,窗口left和right从0开始,right移动过程中每遇到str2中的字符,对应词频-1,小于0也继续-1,当right移动到所有词频都小于等于0时,说明此时[left,right]窗口内全包含了str2,但不一定是最小的,因为其中某个字符可能重复出现多次
- 移动left,每遇到str2中的一个字符,对应词频++,如果词频小于0,说明还是全包含,当left移动过程中,某个词频=0了,说明当前窗口内str2中的某个字符不能再少了,记录当前窗口长度,然后right往右移动,直到所有的词频都再次小于0,继续移动left,当某个字=0了,记录长度,然后重复移动right的逻辑
- 总的来说就是记录所有字符词频,当字符都<=0时,说明此时全包含,移动左边界查找当前最小的子序列,然后继续移动右边界增加新的字符知道再次满足全包含
function process(str1, str2) {
let map = {};
for (let i = 0; i < str2.length; i++) {
if (map[str2[i]]) {
map[str2[i]]++;
} else {
map[str2[i]] = 1;
}
}
let left = 0,
right = 0,
match = str2.length,
minLen = Infinity; // 词频总数
// 如果right到终止位置词频总数还大于0,也就是说right还要++,那说明窗口范围不能满足题目条件,所以终止条件选right而不是left
while (right !== str1.length) {
if (map[str1[right]] !== undefined) {
// 命中 str2 中的元素,
map[str1[right]]--;
if (match > 0) {
match--;
}
}
if (match === 0) {
// 词频记录中只要有一个元素不小于0了,说明当前窗口的right需要往右移补充新的元素,否则该元素数量在窗口内将缺失
while (map[str1[left]] < 0) {
if (map[str1[left]] !== undefined) {
map[str1[left++]]++;
}
minLen = Math.min(minLen, right - left + 1);
match++;
map[str1[left++]]++;
}
}
right++;
}
return minLen;
}