滑动窗口 - LeetCode hot 100

滑动窗口 - LeetCode hot 100

@jarringslee

文章目录

什么是滑动窗口

在我目前接触到的算法题中,滑动窗口应该算是双指针的一个重要的分支应用,通常用于解决数组和字符串的区间问题。

它通过使用双指针维护一个动态窗口,在遍历数据(通常是数组或者字符串)时不断调整窗口边界,从而高效快速地找到题目要求的解。

滑动窗口的核心思想是避免重复计算,将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. 找到字符串中所有字母异位词

给定两个字符串 sp,找到 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;
};
相关推荐
Larcher4 小时前
React Router 不只是页面跳转:从 SPA 路由到权限守卫的完整实践
javascript·后端
Larcher4 小时前
大模型为什么每次回答都不一样?一文搞懂 Temperature、Top K 与 Top P
javascript·后端
.道阻且长.6 小时前
2.LeetCode算法习题讲解--双指针--复写零
算法·leetcode·职场和发展
eric-sjq8 小时前
10 分钟实战:用 0.6B 本地模型生成中文网页(WanlyFrontend + 编译器全流程)
javascript·机器学习·自然语言处理·html
To_OC8 小时前
LC 438 找到所有字母异位词:暴力超时后,我靠滑动窗口一招搞定
javascript·算法·leetcode
kyriewen9 小时前
面试官问"这段逻辑为什么这样写"——我才发现,这半年我写的代码,我自己都解释不了
前端·javascript·面试
一壶浊酒..10 小时前
Scrape Webpack练习
开发语言·javascript·webpack
Forever Nore11 小时前
学完C语言力扣第一题做不来正常吗
数据结构·算法
hansang_IR11 小时前
【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)
c++·算法·并查集