代码随想录算法训练营第2天|209. 长度最小的子数组、59.螺旋矩阵II
LeetCode209
2025-01-23 18:31:09 星期四
题目描述:力扣209
文档讲解:代码随想录(programmercarl)209. 长度最小的子数组
视频讲解:《代码随想录》算法视频公开课:拿下滑动窗口! | LeetCode 209 长度最小的子数组
代码随想录视频内容简记
这道题目仍然是用双指针的思想,如果是暴力解法,用两个for循环,但是双指针的思想就是要用一个for循环来解决问题,所以时间复杂度为
梳理
-
j是起始位置还是终止位置
-
计算滑动窗口元素的和
-
更新数组最小长度subl并缩小滑动窗口
-
关于时间复杂度
这个题真是感觉抽象

大致代码内容
-
首先是关于
for(j = 0; j < nums.size(); j++)
中的这个j
到底指向的是滑动窗口的起始位置还是终止位置?如果是起始位置,那么终止位置就要依然跟着从0开始向后遍历,就和暴力解法一样了。而如果是终止位置,那么只需要采取策略移动起始位置,就可以不断缩小滑动窗口的范围。所以,这里的j
是终止位置 -
计算滑动窗口内部的和需要使用
sums = sums + nums[j]
-
更新数组最小长度subl并缩小滑动窗口。这是滑动窗口内层的while()循环,是
while(sums >= target)
。如何更新数组的最小长度subl?首先需要在开始定义subl为一个Max值,之后不断进行subl = min (subl, j - i)
。那么如何缩小滑动窗口呢?首先需要sums
减掉当前位置的nums[i]
,之后进行i++
操作。
LeetCode测试
这个运行了好多遍一直报错,是有个小坑的。
报错
-
首先是题目描述中说明了“如果不存在符合条件的子数组,返回 0 ”
所以这个需要看清楚,在
return
的时候写清楚0的情况 -
在梳理的第三步
刚开始看视频我没注意写的是“缩小滑动窗口并更新数组最小长度subl”,于是代码就长这样,一直报错,找不出来问题
while (sum >= target) {
// 缩小滑动窗口
sum -= nums[i];
i++;
// 更新数组最小长度
result = j - i + 1;
subl = min(subl, result);
}
按照k哥的方法,全删了重新写了之后发现这样有个问题就是每次的result
计算会没有来得及计算刚开始i值,其就进行了i++
操作,这样显然是不对的,于是修改之后
while (sum >= target) {
sum -= nums[i];
result = j - i + 1;
subl = min(subl, result);
i++;
}
这样就对了,然后现在再一看,就是先“更新数组最小长度subl并缩小滑动窗口”,于是就可以整理的下
while (sum >= target) {
// 更新数组最小长度
result = j - i + 1;
subl = min(subl, result);
// 缩小滑动窗口
sum -= nums[i];
i++;
}
至于为什么非得按照先更新数组最小长度,再缩小滑动窗口,我的理解应该就是上面的Bug。如果先缩小滑动窗口显然会跳过某些i
值,就肯定不对了
滑动窗口代码
这个代码的时间复杂度是,其实确实不太理解,但是k哥讲的是
看每一个元素被操作的次数,每个元素在滑动窗口进来操作一次,出去操作一次,每个元素都被操作两次,所以时间复杂度是也就是
这里的操作应该指的就是sum+和sum-的操作
点击查看代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int i = 0, sum = 0, subl = INT32_MAX, result;
for (int j = 0; j < nums.size(); j++) {
sum += nums[j];
while (sum >= target) {
// 更新数组最小长度
result = j - i + 1;
subl = min(subl, result);
// 缩小滑动窗口
sum -= nums[i];
i++;
}
}
return subl == INT32_MAX ? 0 : subl;
}
};
LeetCode59
题目描述:力扣59
文档讲解:代码随想录(programmercarl)59.螺旋矩阵II
视频讲解:《代码随想录》算法视频公开课:拿下螺旋矩阵!LeetCode:59.螺旋矩阵II
代码随想录视频内容简记
梳理
-
坚持循环不变量原则
这道题目,并没有用到二分法、双指针,但是其思想是和二分法那道题目是一样的。就是要明确在循环中,使用统一的规则进行判断,从而避免各种对边界条件的
if
的复杂讨论。具体到这道题目中,就是使用左闭右开的规则。 -
确定初始位置和确定每一条边循环之后的终止位置
-
循环条件。这个循环条件很重要,刚开始就写错了
-
对生成的矩阵的边的长度进行讨论,具体是奇数还是偶数
大致代码内容
-
startx = 0, starty = 0
,首先给初始位置赋值 -
offset = 1
给终止位置赋值 -
loop = n / 2
,while(loop--)
,这里的判断条件是适用于矩阵边长为偶数的情况,还有一个奇数的情况就是放在最后才加上的 -
四个for循环。
-
最后需要对边为奇数的情况进行单独讨论
nums[mid][mid] = count
LeetCode测试
有几个坑🕳还得记录一下
-
首先是n为奇数时最后的中间变量
刚开始这个写的
nums[i][j] = count
,以为跳出最后的while循环之后直接赋值应该没问题,但是后面用例测试发现这样写,比如n = 3
,最后的9就会把1的位置覆盖掉。一看才发现其实这样写,最后的i--
,减到了0,前一个for循环的j--
也一样,都是减到了0,正好不是正中间,换成其他的n肯定也就不是最中间的位置了 -
然后是一直一直在报错的一个Bug找不到,这个Bug就出在循环条件上面,刚开始的循环条件是这么写的
while (n / 2){
for (j = starty; j < n - offset; j++){
nums[startx][j] = count++;
}
for{}
...
n = n / 2;
}
这里有两个错。第一个是在内部的for循环的条件判断也涉及n
,如果直接这么写内部的n
就被修改了,显然是错的,先修改了第一个之后
int loop = n;
while (loop / 2){
for (j = starty; j < n - offset; j++){
nums[startx][j] = count++;
}
for{}
...
loop = loop / 2;
}
第二个也就是我以为可以写成个loop = loop / 2
,然后循环判断,loop = 0
的时候终止。但是后面在测试用例n=10
出现报错。算一下其实发现,他少算了一个循环应该。如果按照我这么写法,依次是n = 10, n = 5, n = 2, n = 1
结束,但正常的应该是5才对。最终参考k哥的修改
int loop = n / 2;
while (loop--){
for (j = starty; j < n - offset; j++){
nums[startx][j] = count++;
}
for{}
...
}
这样就是n = 5, n = 4, n = 3, n = 2, n = 1
总共5次没有问题了
螺旋矩阵Ⅱ
点击查看代码
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> nums(n, vector<int>(n, 0));
int i, j, startx = 0, starty = 0, offset = 1, count = 1, mid = n / 2;
int loop = n / 2;
while(loop--){
for (j = starty; j < n - offset; j++){
nums[startx][j] = count++;
}
for (i = startx; i < n - offset; i++){
nums[i][j] = count++;
}
for (; j > starty; j--){
nums[i][j] = count++;
}
for (; i > startx; i--){
nums[i][j] = count++;
}
offset++;
startx++;
starty++;
}
if (n % 2 != 0) nums[mid][mid] = count;
return nums;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端