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

本篇文章精选两道 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
窗口最值统计 单调队列

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

相关推荐
superman超哥11 分钟前
仓颉语言中基本数据类型的深度剖析与工程实践
c语言·开发语言·python·算法·仓颉
Learner__Q41 分钟前
每天五分钟:滑动窗口-LeetCode高频题解析_day3
python·算法·leetcode
阿昭L1 小时前
leetcode链表相交
算法·leetcode·链表
闻缺陷则喜何志丹1 小时前
【计算几何】仿射变换与齐次矩阵
c++·数学·算法·矩阵·计算几何
liuyao_xianhui1 小时前
0~n-1中缺失的数字_优选算法(二分查找)
算法
hmbbcsm2 小时前
python做题小记(八)
开发语言·c++·算法
机器学习之心2 小时前
基于Stacking集成学习算法的数据回归预测(4种基学习器PLS、SVM、BP、RF,元学习器LSBoost)MATLAB代码
算法·回归·集成学习·stacking集成学习
图像生成小菜鸟2 小时前
Score Based diffusion model 数学推导
算法·机器学习·概率论
声声codeGrandMaster2 小时前
AI之模型提升
人工智能·pytorch·python·算法·ai
黄金小码农3 小时前
工具坐标系
算法