algorighm/top-interview-leetcode150/sliding-Window/438找到字符串中所有字母异位词.js

113 lines
3.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* https://leetcode.cn/problems/find-all-anagrams-in-a-string/
* @param {string} s
* @param {string} p
* @return {number[]}
*/
const findAnagrams = function (s, p) {
};
/*
按照暴力解法的话我们可能会把p的所有异位词都枚举出来之后遍历遍历所有的异位词利用indexof查看每一个异位词在s中的位置如果
这个异位词在s中存在那么就把起始下标放入到结果集中如果p非常长的话那么所有异位词就是一个长度的全排列!m,加上对s的查找那就是一个
(n+m)*!m, 这显然是不能接受的,所以我们需要换一种思路.
思路异位词和原词在单词数量上是一致的所以我们可以维护一个在s上长度位p.length的窗口只要这个窗口里面所有单词出现的数量和
p中所有单词出现的数量一致的话那么就认为这个窗口表示的单词是p的一个异位词最后只需把窗口的起始下标放入结果集合即可
*/
function f1(s, p) {
const result = []; // 返回的结果集
if (s.length < p.length) return result; // p比s还长在s中不可能有p的异位词直接返回
const need = new Map(); // 记录p中每一个词出现的次数用于验证异位词
const window = new Map(); // 记录当前窗口中的异位词
// 统计p的所有字符出现的次数
for (const char of p) {
need.set(char, (need.get(char) || 0) + 1);
}
let left = 0; // 滑动窗口的左边界
let right = 0; // 滑动窗口的右边界
let valid = 0; // 滑动窗口中符合异位字的字符数量;
while (right < s.length) {
const char = s[right];
if (need.has(char)) {
window.set(char, (window.get(char) || 0) + 1);
if (window.get(char) === need.get(char)) {
valid++;
}
}
// 如果窗口长度等于异位字符p的长度那么就检测当前窗口是否是一个异位词
if (right - left + 1 === p.length) {
if (valid === need.size) {
result.push(left); // 把left添加到结果集中
}
const leftChar = s[left];
// 收缩窗口
left++;
// 判断收缩掉的这个字符是否是need中的某一个字符
if (need.has(leftChar)) {
if (window.get(leftChar) === need.get(leftChar)) {
valid--; // 验证符合异位词字符个数的词减1
}
window.set(leftChar, window.get(leftChar) - 1); // 使这个字符的数量减1
}
}
// 扩展窗口
right++;
}
return result;
}
function f3(s, p) {
const result = []; // 返回的结果集
if (s.length < p.length) return result; // p比s还长在s中不可能有p的异位词直接返回
const need = new Map(); // 记录p中每一个字符出现的次数用于验证异位词
const window = new Map(); // 记录当前窗口中的异位词
// 统计p的所有字符出现的次数
for (const char of p) {
need.set(char, (need.get(char) || 0) + 1);
}
let left = 0; // 滑动窗口的左边界
let right = 0; // 滑动窗口的右边界
while (right < s.length) {
const char = s[right];
// 扩展窗口
window.set(char, (window.get(char) || 0) + 1);
// 如果当前窗口大小达到p的长度判断是否为异位词
if (right - left + 1 === p.length) {
// 比较窗口内字符的频次是否和p中一致
let isAnagram = true;
for (const [key, value] of need) {
if (window.get(key) !== value) {
isAnagram = false;
break;
}
}
if (isAnagram) {
result.push(left); // 将符合条件的起始索引加入结果
}
// 收缩窗口
const leftChar = s[left];
window.set(leftChar, window.get(leftChar) - 1); // 减少左边字符的频次
if (window.get(leftChar) === 0) {
window.delete(leftChar); // 如果频次为0移除该字符
}
left++; // 移动左指针
}
// 扩展右指针
right++;
}
return result;
}