209.长度最小的子数组
1. 资源
题目建议: 本题关键在于理解滑动窗口,这个滑动窗口看文字讲解 还挺难理解的,建议大家先看视频讲解。 拓展题目可以先不做。
文章讲解:programmercarl.com/0209.%E9%95…
视频讲解:www.bilibili.com/video/BV1tZ…
2. 个人总结
2.1. 算法原理
在数组中维护一段“连续区间”的统计信息,并通过左右指针移动来更新区间,使算法从 O(n²) 变成 O(n)。
- 举个最简单的例子:
找数组中连续长度为 3 的子数组的最大和。
你当然可以写三层循环不停算,但很慢。
滑动窗口的想法是:
“窗口右边加进一个元素,同时让窗口左边丢掉一个元素。”
你就可以用 O(1) 的代价更新窗口的和,而不是从头算和。
- 核心流程(通用)
可以总结为 4 步:
- 右指针右移:让窗口扩大
- 更新窗口内部记录(和、频率等)
- 当窗口不满足题目条件时
→ 移动左指针收缩窗口 - 此时窗口满足条件
→ 记录结果(最大/最小/计数等)
2.2. 应用前提
前提 1:问题必须基于 “连续区间”
滑动窗口的窗口是一段 连续的子数组/子串。
所以它只能解决:
连续子数组
连续子串
连续序列
前提 2:窗口的统计信息能通过“增量更新”维护
也就是:
当右边进一个元素、左边出一个元素时,
你能快速(O(1))更新窗口状态,而不是重新计算整个区间。
比如:
- 求和:
sum += 新元素 - 老元素 - 求频率:
freq[x]++ / freq[y]-- - 判断是否满足条件:哈希表 可 O(1) 判断
- 最小值/最大值:双端队列维护
前提 3:窗口扩张/收缩必须是“单调移动”
左右指针必须满足:
- 右指针只往右走,不回头
- 左指针也只往右走,不回头
如果解题需要指针来回跳,就不适合。
这样整个算法才是 O(n)。
2.3. 注意点
- 外层遍历的指针到底是窗口的终止位置指针还是起始位置指针
应该是终止位置。先起始位置不变,通过不断右移终止位置,拉长区间,一旦区间内统计值满足要求就停止,再左移区间起始位置,使在当前情况下,最小区间满足要求。在向右移动区间,重复上述过程,期望有更短的区间存在。
2.4. 代码:
暴力解法
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int minSize = n + 1;
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += nums[j];
if (sum >= target) {
minSize = min(minSize, j - i + 1);
break; // 第一个满足的 j 即为该起点的最短长度
}
}
}
return minSize == n + 1 ? 0 : minSize;
}
};
滑动窗口 (双指针)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int reuslt = nums.size() + 1;
int i = 0; //指向窗口起始位置
int sum = 0;
for(int j = 0;j<nums.size();j++)
{//指向窗口终止位置
//获得窗口内元素之和
sum += nums[j];
while(sum >= target)
{//合适的窗口大小
reuslt = min(reuslt, j-i +1);
//移动窗口起始位置,再循环下一次,判断缩小窗口后是否还满足
sum = sum - nums[i];
i++;
}
//找到了一个最小窗口大小,但是还没遍历完,窗口终止位置继续右移,重复上述过程
}
return reuslt == nums.size()+1 ? 0 : reuslt;
}
};
59.螺旋矩阵II
1. 资源
题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
文章讲解:programmercarl.com/0059.%E8%9E…
视频讲解:www.bilibili.com/video/BV1SL…
2. 个人总结
这部分目前来看就是心里明白,一写就乱,这部分没什么算法可讲,就是自己推。得保证自己的边界处理正确,其间不会思维混乱(真的很麻烦,写着写着就忘乎所以了)
2.1. 注意点
注意,边界一致原则,注意转每圈的四个临界点。视频里面采用的方式是 左闭右开。遍历第一行最右边的点不处理;遍历右边第一列,最下面的点不处理;遍历底边,从右到左,最后一个点(最左边点不处理)
2.2. 代码