滑动窗口 - LeetCode hot 100
@jarringslee
文章目录
- [滑动窗口 - LeetCode hot 100](#滑动窗口 - LeetCode hot 100)
-
- 什么是滑动窗口
- 滑动窗口的两种类型
- 算法题
-
- [3. 无重复字符的最长子串(https://leetcode.cn/problems/longest-substring-without-repeating-characters/)](#3. 无重复字符的最长子串)
- [438. 找到字符串中所有字母异位词(https://leetcode.cn/problems/find-all-anagrams-in-a-string/)](#438. 找到字符串中所有字母异位词)
什么是滑动窗口
在我目前接触到的算法题中,滑动窗口应该算是双指针的一个重要的分支应用,通常用于解决数组和字符串的区间问题。
它通过使用双指针维护一个动态窗口,在遍历数据(通常是数组或者字符串)时不断调整窗口边界,从而高效快速地找到题目要求的解。
滑动窗口的核心思想是避免重复计算,将O(n2)的暴力循环转化为O(n),更加高效。
滑动窗口的两种类型
快慢指针:用于链表中的环检测或中点查找。
左右指针:用于数组或字符串的两端向中间遍历(如二分查找或两数之和)。
滑动窗口指针:左右指针维护一个窗口,通过移动指针调整窗口范围。
算法题
3. 无重复字符的最长子串
给定一个字符串
s,请你找出其中不含有重复字符的 最长 子串 的长度。
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。注意 "bca" 和 "cab" 也是正确答案。
用集合实现滑动窗口
建立双指针, 右指针往前走,直到窗口中出现相同字符(即左右指针字符相同)则左指针往前走,直到窗口中无重复字符(或指针相遇)为止。
本题可利用Set集合自动去重的特性来建立滑动窗口。右指针通过for循环来遍历字符串,期间判断Set集合中是否有重复字符,有重复就删除重复字符并走左指针,直到不重复,然后加上当前字符,更新当前窗口长度(如果比上一次大)。
js
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let ans = 0; // 窗口长度 初始化为0
let left = 0; // 左指针
const window = new Set(); // 建立集合作为滑动窗口
for (let right = 0; right < s.length; right++) {
const str = s[right];
while (window.has(str)) { // while循环重复检测是否有重复
window.delete(s[left]);
left++; // 有的话就删除并走左指针
}
window.add(str); // 添加当前子串
ans = Math.max(ans, right - left + 1); // 更新最大长度
}
return ans;
};
438. 找到字符串中所有字母异位词
给定两个字符串
s和p,找到s中所有p的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。 输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
滑动窗口 + 哈希表判断储值是否全等
由于:"abc" "cab" 都算作 "abc" 的异位词,且在 "abcab" 中 一共出现了 "abc" "bca" "cab"三组异位词,那么我们可以:
对于和目标字符串p的比较,我们可以建立两个哈希表,储存对应的字母的出现次数;对于给定子串s,我们建立滑动窗口,用for遍历右指针:每次先储存右指针的值,然后先判断窗口长度是否超过目标串,超过就删去左指针对应的值并让左指针前移一位,最后判断长度是否相等,相等就遍历比较两个哈希表的键值对,全等就将左指针下标push进答案数组。
- 建立哈希表,储存目标串
- 初始化滑动窗口哈希表,左指针和答案数组
- 利用右指针建立for循环
- 储存右值
- 窗口过大就删一个左值
- 窗口相等就判断哈希表
js
var findAnagrams = function(s, p) {
let need = new Map();
for (let i = 0; i < p.length; i++) {
need.set(p[i], (need.get(p[i]) || 0) + 1);
}
let window = new Map();
let left = 0;
let ans = [];
for (let right = 0; right < s.length; right++) {
const str = s[right];
window.set(str, (window.get(str) || 0) + 1);
if (right - left + 1 > p.length) {
if(window.get(s[left]) === 1) window.delete(s[left]);
else window.set(s[left], window.get(s[left]) - 1);
left++;
}
if (right - left + 1 == p.length){
let flag = true;
for (let [key,value] of need) {
if (window.get(key)!== value) flag=false;
}
if (flag) ans.push(left);
}
}
return ans;
};