本篇文章精选两道 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 |
| 窗口最值统计 | 单调队列 |
把这两招吃透,将极大提升字符串和滑动窗口题处理能力