- 求出字符串的「字谜」
字谜:两个字符串每个字符出现次数相同只是顺序不同,则互为字谜
tip: 滑动窗口,校验次数
/**
* @param {string} s
* @param {string} p
* @return {number[]}
*/
var findAnagrams = function(s, p) {
let map = {}, count = 0, ans = [];
var resetMap = () => {
for (let key in map) {
if(map.hasOwnProperty(key)) {
map[key].count = map[key].originCount;
}
}
count = 0;
}
for (let i = 0; i < p.length; i++) {
if (map[p[i]]) {
map[p[i]].count++;
map[p[i]].originCount++;
} else {
map[p[i]] = {
count: 1,
originCount: 1
};
}
}
let i = 0, j = 0;
while (j < s.length) {
if (map[s[j]] && map[s[j]].count > 0) {
//字符数-1, 匹配数+1
map[s[j]].count--;
count++;
//完成了匹配
if (count == p.length) {
ans.push(i);
j++;
while(s[i] == s[j]) {
i++;
ans.push(i);
j++;
}
map[s[i]].count++;
count--;
i++;
} else {
j++;
}
} else {
if (!map[s[j]]) {
//不可能从j开始,窗口滑动,从头开始。
j++;
i = j;
resetMap();
} else {
while(s[i] != s[j]) {
map[s[i]].count++;
count--;
i++;
}
i++;
j++;
}
}
}
return ans;
};
- 至多包含k个不同字符的最长子串
解法:维持大小为k的滑动窗口。 遇到元素出现过,无脑移动 遇到元素未出现过,对窗口左侧进行收敛 利用map记录元素出现的次数
/**
* @param {string} s
* @param {number} k
* @return {number}
*/
var lengthOfLongestSubstringKDistinct = function(s, k) {
if (k == 0) return 0;
let map = {}, max = 0, count = 0;
let i = 0, j = 0;
//滑动窗口。保持窗口内只有K个不同字符
while (j < s.length) {
//s[j]没有出现过
if (!map[s[j]]) {
//字符计数+1
count++;
map[s[j]] = 1;
//如果窗口超过k,那么左边需要收敛,直到窗口大小重新变成K
while (count > k) {
map[s[i]]--;
if (map[s[i]] == 0) {
count--;
}
i++;
}
} else {
//出现过,则无脑向前,计数+1
map[s[j]]++;
}
max = Math.max(max, j - i + 1);
j++;
}
return max;
};
- 长度最短的和为k的连续子序列
序列连续则考虑滑动窗口
left, right初始为0,right依次向右求和 和小于k, right向右 和大于k,left向右 等于k时,不断比较长度
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
var min = nums.length, left = 0, right = -1, sum = 0, flag = false;
nums.forEach((num, index) => {
sum += num;
right++;
while(sum >= target) {
flag = true;
if (right - left + 1 < min) {
min = right - left + 1;
}
sum -= nums[left];
left++;
}
});
return flag ? min : 0;
};