代码随想录算法训练营第2天|209. 长度最小的子数组、59.螺旋矩阵II

LeetCode209

2025-01-23 18:31:09 星期四

题目描述:力扣209
文档讲解:代码随想录(programmercarl)209. 长度最小的子数组
视频讲解:《代码随想录》算法视频公开课:拿下滑动窗口! | LeetCode 209 长度最小的子数组

代码随想录视频内容简记

这道题目仍然是用双指针的思想,如果是暴力解法,用两个for循环,但是双指针的思想就是要用一个for循环来解决问题,所以时间复杂度为O(n)

梳理

  1. j是起始位置还是终止位置

  2. 计算滑动窗口元素的和

  3. 更新数组最小长度subl并缩小滑动窗口

  4. 关于时间复杂度O(n)

    这个题真是感觉抽象

大致代码内容

  1. 首先是关于for(j = 0; j < nums.size(); j++)中的这个j到底指向的是滑动窗口的起始位置还是终止位置?如果是起始位置,那么终止位置就要依然跟着从0开始向后遍历,就和暴力解法一样了。而如果是终止位置,那么只需要采取策略移动起始位置,就可以不断缩小滑动窗口的范围。所以,这里的j是终止位置

  2. 计算滑动窗口内部的和需要使用sums = sums + nums[j]

  3. 更新数组最小长度subl并缩小滑动窗口。这是滑动窗口内层的while()循环,是while(sums >= target)。如何更新数组的最小长度subl?首先需要在开始定义subl为一个Max值,之后不断进行subl = min (subl, j - i)。那么如何缩小滑动窗口呢?首先需要sums减掉当前位置的nums[i],之后进行i++操作。

LeetCode测试

这个运行了好多遍一直报错,是有个小坑的。

报错

  1. 首先是题目描述中说明了“如果不存在符合条件的子数组,返回 0 ”

    所以这个需要看清楚,在return的时候写清楚0的情况

  2. 在梳理的第三步

    刚开始看视频我没注意写的是“缩小滑动窗口并更新数组最小长度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值,就肯定不对了

滑动窗口代码

这个代码的时间复杂度是O(n),其实确实不太理解,但是k哥讲的是

看每一个元素被操作的次数,每个元素在滑动窗口进来操作一次,出去操作一次,每个元素都被操作两次,所以时间复杂度是2×n也就是O(n)

这里的操作应该指的就是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

代码随想录视频内容简记

梳理

  1. 坚持循环不变量原则

    这道题目,并没有用到二分法、双指针,但是其思想是和二分法那道题目是一样的。就是要明确在循环中,使用统一的规则进行判断,从而避免各种对边界条件的if的复杂讨论。具体到这道题目中,就是使用左闭右开的规则。

  2. 确定初始位置和确定每一条边循环之后的终止位置

  3. 循环条件。这个循环条件很重要,刚开始就写错了

  4. 对生成的矩阵的边的长度进行讨论,具体是奇数还是偶数

大致代码内容

  1. startx = 0, starty = 0,首先给初始位置赋值

  2. offset = 1给终止位置赋值

  3. loop = n / 2while(loop--),这里的判断条件是适用于矩阵边长为偶数的情况,还有一个奇数的情况就是放在最后才加上的

  4. 四个for循环。

  5. 最后需要对边为奇数的情况进行单独讨论nums[mid][mid] = count

LeetCode测试

有几个坑🕳还得记录一下

  1. 首先是n为奇数时最后的中间变量

    刚开始这个写的nums[i][j] = count,以为跳出最后的while循环之后直接赋值应该没问题,但是后面用例测试发现这样写,比如n = 3,最后的9就会把1的位置覆盖掉。一看才发现其实这样写,最后的i--,减到了0,前一个for循环的j--也一样,都是减到了0,正好不是正中间,换成其他的n肯定也就不是最中间的位置了

  2. 然后是一直一直在报错的一个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;
    }
};
posted on   bnbncch  阅读(2448)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示