9.找到字符串中所有字母异位词(学习)
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。
示例 2:
输入: s = “abab”, p = “ab”
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的异位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
var findAnagrams = function(s, p) {
const result = [];
const pLength = p.length;
const sLength = s.length;
// 如果p的长度大于s,则不可能存在p的异位词
if (pLength > sLength) {
return result;
}
// 初始化两个哈希表,分别用于存储p和当前窗口的字符频率
const pFreq = {};
const windowFreq = {};
// 填充pFreq哈希表
for (let char of p) {
if (!pFreq[char]) {
pFreq[char] = 0;
}
pFreq[char]++;
}
// 初始化窗口
let left = 0;
let matched = 0; // 记录当前窗口内匹配p的字符数量
// 滑动窗口
for (let right = 0; right < sLength; right++) {
const char = s[right];
// 如果当前字符在p中,则增加其频率
if (pFreq[char]) {
if (!windowFreq[char]) {
windowFreq[char] = 0;
}
windowFreq[char]++;
// 如果当前字符的频率与p中一致,则增加匹配数
if (windowFreq[char] === pFreq[char]) {
matched++;
}
}
// 当窗口大小等于p的长度时,检查是否所有字符都匹配
if (right - left + 1 === pLength) {
// 如果匹配数等于p中字符的种类数,则找到了一个异位词
if (matched === Object.keys(pFreq).length) {
result.push(left);
}
// 移动左指针,并更新窗口频率
const leftChar = s[left];
if (pFreq[leftChar]) {
if (windowFreq[leftChar] === pFreq[leftChar]) {
matched--;
}
windowFreq[leftChar]--;
// 如果窗口频率中该字符为0,则删除该键
if (windowFreq[leftChar] === 0) {
delete windowFreq[leftChar];
}
}
left++;
}
}
return result;
};