每天五分钟:滑动窗口-LeetCode高频题解析_day3

3. 无重复字符的最长子串

把字符串想象成一排小格子,每格一个字母。

有一辆"窗口小火车"在这排格子上滑动,它有:

  • 左车门:left

  • 右车门:right

规则:

  • 火车载的乘客 = 当前子串里的字母

  • 不能有重名的乘客(无重复字符)

做法:

  1. right 每次往右走一格,把新字母拉上车

  2. 如果发现车里已经有同名乘客了

    → 就从左边寻找到同名乘客,都"请下车"(left = max(left, char_map[cur] + 1))

  3. 每一次火车停下来的时候,记录车里乘客人数(窗口长度)

  4. 记住历史上最多的一次乘客数,就是答案


核心算法思路(滑动窗口)

  • 用一个 setdict 记录窗口中出现的字符

  • right 往右走遍历字符串

  • s[right] 没出现在窗口中 → 直接加入

  • res = max(res, right - left) 更新答案

  • 若已经出现 → 移动 left到char_map中的同名索引;并从窗口中删字符

时间复杂度:O(n),每个字符最多进窗口一次、出窗口一次。

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        char_map = {} #字典,用来存储每个字符最近出现的位置(索引)
        left = 0
        res = 0

        for right in range(len(s)):
            cur = s[right]
            if cur in char_map:
                res = max(res, right - left)
                # 注意这一步,非常重要!排除了虽然存在,但在窗口之外的
                left = max(left, char_map[cur] + 1)
            char_map[cur] = right
        
        return max(res, len(s) - left)

438. 找到字符串中所有字母异位词

"开一个长度等于 p 的小窗,

每挪动一步,更新窗里的字母数量,
只要数量表和 p 一样,这个位置就是答案。"


核心算法思路(定长滑动窗口)

  • 窗口长度固定为 k = len(p)

  • 用数组/字典统计 p 中每个字母的次数 need

  • 再用同样的结构维护窗口中每个字母的次数 window

  • 每次移动一格:

    • 右边加一个字母

    • 左边减一个字母(保证窗口长度始终为 k)

  • window == need,说明当前窗口是一个异位词 → 记录左端点

python 复制代码
from collections import Counter

class Solution:
    def findAnagrams(self, s: str, p: str):
        n, k = len(s), len(p)
        if n < k:
            return []

        need = Counter(p)
        window = Counter()
        res = []

        left = 0
        for right in range(n):
            # 把右边新字符加进窗口
            window[s[right]] += 1

            # 保持窗口长度为 k
            if right - left + 1 > k:
                window[s[left]] -= 1
                if window[s[left]] == 0:
                    del window[s[left]]
                left += 1

            # 长度刚好是 k 时,比较两边字母袋
            if right - left + 1 == k and window == need:
                res.append(left)

        return res

239. 滑动窗口最大值

有一个"魔法队伍",它只做两件事:

  1. 只保留可能成为最大值的同学

  2. 队伍里的数字从前到后是从大到小排好的

窗口往右移动时:

  • 新同学要进来时:

    • 把队尾比他小或等于他的同学全赶走(因为以后不可能当最大值)

    • 然后自己站到队尾

  • 如果队头同学已经"走出窗口范围"

    → 把他从队头移除

  • 每次窗口形成一个完整长度 k 后,

    → 队头的那位就是当前窗口的最大值


核心算法思路(单调队列 + 滑动窗口)

  • deque 存储的是 下标,不直接存值

  • 队列中的下标,对应的 nums[index]从大到小

  • 维护规则:

    1. 进新元素 i 前,从队尾把所有 nums[队尾] <= nums[i] 的下标弹出

    2. i 放入队尾

    3. 如果队头下标 < i - k + 1,说明已经不在当前窗口中,弹出队头

    4. i >= k - 1 时,开始记录答案:res.append(nums[deque[0]])

时间复杂度:O(n),每个元素最多入队一次出队一次。

python 复制代码
from collections import deque

class Solution:
    def maxSlidingWindow(self, nums, k: int):
        q = deque()   # 存下标,保持对应值单调递减
        res = []

        for i, x in enumerate(nums):
            # 1. 保持队列单调递减:新来的比队尾大,就把队尾弹掉
            while q and nums[q[-1]] <= x:
                q.pop()

            # 2. 把当前下标入队
            q.append(i)

            # 3. 如果队头已经滑出窗口左边,就弹掉
            if q[0] <= i - k:
                q.popleft()

            # 4. 当 i >= k-1 时,窗口已经形成,可以记录最大值
            if i >= k - 1:
                res.append(nums[q[0]])

        return res
相关推荐
————A2 小时前
强化学习----->轨迹、回报、折扣因子和回合
人工智能·python
阿昭L2 小时前
leetcode链表相交
算法·leetcode·链表
闻缺陷则喜何志丹2 小时前
【计算几何】仿射变换与齐次矩阵
c++·数学·算法·矩阵·计算几何
liuyao_xianhui2 小时前
0~n-1中缺失的数字_优选算法(二分查找)
算法
徐先生 @_@|||2 小时前
(Wheel 格式) Python 的标准分发格式的生成规则规范
开发语言·python
Mqh1807623 小时前
day45 简单CNN
python
hmbbcsm3 小时前
python做题小记(八)
开发语言·c++·算法
机器学习之心3 小时前
基于Stacking集成学习算法的数据回归预测(4种基学习器PLS、SVM、BP、RF,元学习器LSBoost)MATLAB代码
算法·回归·集成学习·stacking集成学习
图像生成小菜鸟3 小时前
Score Based diffusion model 数学推导
算法·机器学习·概率论