从零开始刷算法——字串与区间类经典题:前缀和 + 单调队列双杀

本篇文章精选两道 LeetCode 高频题:

  • 560. 和为 K 的子数组

  • 239. 滑动窗口最大值

分别代表:

✔ 前缀和 + 哈希表

✔ 双端队列 + 单调队列

这些都是处理 连续区间 / 字串类问题核心技巧,非常适合面试冲刺与能力提升。


一、和为 K 的子数组(前缀和 + 哈希)

题目要求:找到连续子数组,使得它们的和为 k,并返回数量。


解题思路

看到"连续子数组 " + " " → 第一个就要想到 前缀和 PrefixSum

定义前缀和:

cpp 复制代码
s[i] 表示前 i 个元素的和
s[0] = 0 (空数组的和)
s[1] = nums[0] (空数组的和)
s[2] = nums[0] + nums[1]
.....

那么子数组 nums[j..i-1] 的和:

cpp 复制代码
s[i] - s[j] == k  
→ s[i] - k == s[j]

即:
当前前缀和 s[i] 只要能在历史里找到 s[i] - k 的数量,就是答案增加的数量

为了速度:

✔ 用 unordered_map 存储每一种前缀和出现次数

✔ 边遍历边统计


代码实现

cpp 复制代码
class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        // 思路: 看到和就想到前缀和,这时候问题就变成了找s[i] - s[j] = k,所以就可以用hashmap了,那注意点就是前缀和的时候s[i + 1] 来表示前i个数的和。
        int ans = 0;
        vector<int> s(nums.size() + 1);
        for (int i = 0; i < nums.size(); ++i) {
        s[i + 1] = s[i] + nums[i];   // 这里的s[i + 1] 指代的是下标一直到i的和,目的方便计算
        }
        unordered_map<int, int> mp;
        for (int i = 0; i < s.size(); ++i) {
            ans += mp.count(s[i] - k)? mp[s[i] - k] : 0;
            mp[s[i]]++;
        }
        return ans;
    

    }
};

技巧总结

知识点 解释
前缀和 s[0]=0 用来处理从 index=0 开始的子数组
mp 存 prefixSum 次数 避免双循环,时间优化为 O(n)
s[i+1] 定义方式 表示前 i 个元素

二、滑动窗口最大值(单调队列)

维护滑动窗口中最大值

要求 O(n) 时间完成


解题思路

使用 双端队列 deque

但队列内放 下标 + 保持 单调递减(存储的值从头大到尾)

滑动时分 3 步:

步骤 动作
进入窗口 新元素入队前,把小于它的都删掉(维护单调性)
离开窗口 队头元素如果滑出窗口则踢掉(维护最多三个元素)
记录答案 队头就是窗口最大值(因为是单调的,左边就是答案)

飞机看山峰的形象比喻

想象你在飞机上:

  • 山峰(数字)不断进入视野

  • 小山峰被大山峰遮挡(队列维护递减)

  • 离开视野的山峰要从队头弹出

  • 每一刻最高峰就是答案

这样理解非常丝滑!


代码实现

cpp 复制代码
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        // 思路: 想象自己正在坐飞机看外面的山峰,双向队列来记录,同时维护单调性(单调递减)
        vector<int> ans;
        deque<int> q;
        for (int i = 0; i < nums.size(); ++i) {
            // 1.进入
            while (!q.empty() && nums[i] > nums[q.back()]) {
                q.pop_back();
            }
            // 注意这里放下标, 方便后面的判断山峰是否离开视野。
            q.push_back(i);
            // 2.出, 来维护队列只有三个元素
            int left = i - k + 1;
            if (q.front() < left) {  // 注意这里不能用size作比较,因为它维护了单调性删掉了一部分,所以deque不是所有的元素
                q.pop_front();
            }
            // 3.记录答案
            if (left >= 0) {
                ans.push_back(nums[q.front()]);
            }
        }
        return ans;
        
    }
};

总结表

方法 核心思想 时间复杂度 空间复杂度
前缀和 + 哈希 s[i] - s[j] = k O(n) O(n)
单调队列 O(1) 得到窗口最大 O(n) O(k)

文章总结

题型方向 推荐套路
连续子数组求和 前缀和 + Hash
窗口最值统计 单调队列

把这两招吃透,将极大提升字符串和滑动窗口题处理能力

相关推荐
坚持就完事了40 分钟前
十大排序算法
数据结构·算法·排序算法
im_AMBER1 小时前
Leetcode 63 定长子串中元音的最大数目
c++·笔记·学习·算法·leetcode
小白程序员成长日记2 小时前
2025.11.29 力扣每日一题
数据结构·算法·leetcode
在黎明的反思3 小时前
进程通信之消息队列(IPC)
算法
老鱼说AI3 小时前
算法基础教学第一步:数据结构
数据结构·python·算法
Jing_Rainbow3 小时前
【LeetCode Hot100 刷题日记(19/100)】54. 螺旋矩阵 —— 数组、矩阵、模拟、双指针、层序遍历🌀
算法·面试·程序员
地平线开发者4 小时前
征程 6 | linear 高精度输出配置方式
算法·自动驾驶
小尧嵌入式5 小时前
C++基础语法总结
开发语言·c++·stm32·单片机·嵌入式硬件·算法
white-persist5 小时前
【攻防世界】reverse | IgniteMe 详细题解 WP
c语言·汇编·数据结构·c++·python·算法·网络安全