Day2 力扣数组 : 977.有序数组的平方 | 209.长度最小的子数组 | 59.螺旋矩阵II

Day2 力扣数组 : 977.有序数组的平方 | 209.长度最小的子数组 | 59.螺旋矩阵II

977.有序数组的平方

题目建议: 本题关键在于理解双指针思想

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep

第一印象:

这道题我之前做过,在看到双指针的提示之后,一下就想起来了。最大的数字只在两端,比如-4,-1,0,2,3,依次比较两头数字平方的大小,取平方大的加入新数组,然后指针移动就行了。-4平方比3大,16加入新数组,再比较-1和3,3平方比-1大,9加入新数组,再比较-1和2,依次进行。

看完题解的思路:

和我想的一样,我是天才。

实现中的困难:

循环条件判断的不对,最后快慢指针会指向同一个元素,如果写成while (slow < fast) 就会在 slow 和 fast 相等的时候跳出循环。乍一下想好像没什么问题,但是仔细想一下上一步
在这里插入图片描述
这时比较1和3的平方大小,选择3的平方9加入了新数组,然后fast指针向左移动,才会有slow和fast都指向1的情况出现。这个时候元素 1 并没有加入新的数组,所以如果此时跳出循环,就会落下元素 1。所以循环条件应该是while (slow <= fast)

感悟:
我第二次做就能记住是怎么做的了,说明这道题没什么难度,主要还是昨天学的双指针的应用吧,再就是循环终止条件的判断,这个取不取等、减不减 1 我经常需要思考一阵子。

最后附上本题代码:
我对没有负数的情况单独讨论了,其实没必要。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        int[] result = new int[nums.length];
        int index = nums.length - 1;

        if (nums[left] >= 0) {
            for (int i = 0; i < nums.length; i++) {
                result[i] = nums[i] * nums[i];
            }
        } else {
            while (left <= right) {
                if ((nums[left] * nums[left]) < (nums[right] * nums[right])) {
                    result[index] = nums[right] * nums[right];
                    right--;
                    index--;
                } else {
                    result[index] = nums[left] * nums[left];
                    left++;
                    index--;
                }
            }
        }
        return result;
    }
}

209.长度最小的子数组

题目建议: 本题关键在于理解滑动窗口,这个滑动窗口看文字讲解 还挺难理解的,建议大家先看视频讲解。 拓展题目可以先不做。

题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE

第一印象:
  第一下就想到暴力解法了,尝试动手做了一下,也有一些地方需要修改,我用的while循环,不如题解里两个for循环来的直接。超时之后我就去学题解里的滑动窗口思路了,其实也是双指针。

看完题解的思路:
  使用滑动窗口的思路,可以将两层for循环变成一层。
  关键点在于

  • for循环里的变量是快指针还是慢指针?
  • 如何更新慢指针?

for循环里的变量是快指针还是慢指针?:
  倘若for循环中是慢指针,那么在循环内就要不断移动快指针,又陷入了暴力解法的怪圈,所以for循环内要写快指针,在循环体中去移动慢指针。

如何更新慢指针?
  每一次循环 fast 后移一个单位,窗口长度+1,元素求和sum加入 fast 指向的元素。当 sum 满足题意 sum >= target之后,就要移动 slow,缩小窗口 sum 减去慢指针的元素,如果仍然满足 sum >= target,就继续移动,直到不满足条件,此时这个窗口大小就是一个较小的。也可以理解成是 fast 指针满足条件不动之后,移动慢指针仍然能满足条件的最小的窗口。更新minSize的值,继续for循环移动 fast 指针,循环往复,不断更新minSize的值,找到最小的窗口大小,就是答案了。
  可能读者会有和我一样的疑问,在这个过程中不会落下更小的值吗?我看完题解这个过程也感觉有这种想法,也说不上来为什么,就是感觉没有暴力解法那样每种情况都考虑到。但仔细思考一下,题目要求是连续的子数组,而这个窗口也是连续的,fast不断扩大窗口,满足条件之后,slow不断缩小窗口,不满足了 fast 再继续扩大。你去想象这个窗口变化的过程,其实是都覆盖到了的,只有满足条件才会去尝试更新minSize,不满足就改变窗口大小。

实现中的困难:
  明白思路之后,这道题代码实现上其实没什么困难。

 int minSize = Integer.MAX_VALUE;

初始化的时候要让minSize是最大的,这样才能如果比他小,就更新minSize。
再者,窗口大小是 size = j - i + 1;

感悟:
  双指针里的滑动窗口问题,感觉应该是要学会这一类问题。

最后附上代码:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum = 0;
        int size = 0;
        int minSize = Integer.MAX_VALUE;
        int i = 0;

        for (int j = 0; j < nums.length; j++) {
            sum = sum + nums[j];
            while (sum >= target) {
                size = j - i + 1;
                if (size < minSize) {
                    minSize = size;
                }
                sum = sum - nums[i];
                i++;
            }
        }
        return minSize == Integer.MAX_VALUE ? 0 : minSize;
    }
}

59.螺旋矩阵II

题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。

题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/

第一印象:
  看到就感觉写不出来,思路是有的,我知道要保持循环不变量的原则,但是写不出来,还要考虑奇数偶数的问题。

看完题解的思路:
  确实比较复杂,边界条件的处理,还有起始位置、偏移量的声明。我自己写的时候没有想到要声明这些,只想着在循环的过程中去加加减减了。感觉更像个脑筋急转弯,而不是什么算法,是现场去找规律的那种题,好麻烦啊。

就简单写一下思路吧。
在这里插入图片描述
第一圈,从(0,0)开始走到(0,2),(0,0)其实是这一圈的起始位置(startx,starty),循环赋值

int j = starty;
int i = startx;
for (; j < n - 1; j++) {
    result[startx][j] = count++;
}

但细看,第二圈for循环中难道也是 j < n - 1吗?第二圈到(1,1)就停下了,是n-2。那这个语句就不适用于每一圈,于是引入了offset这个偏移量。
正方形,搞清楚要跑几圈。
四条边,搞清楚每条边从哪到哪。
最后如果最中间有值的话就填进去。

实现中的困难:
  就是正方形,搞清楚要跑几圈。四条边,搞清楚每条边从哪到哪。最后如果最中间有值的话就填进去。仔细看题解代码,其实也不难。就是麻烦的1b。

感悟:
  我称其为脑筋急转弯类问题,好烦啊!!

最后附上代码:

class Solution {
    public int[][] generateMatrix(int n) {
        int startx = 0; //每一圈的起始位置
        int starty = 0;
        int offset = 1; //每一圈的偏移量
        int count = 1;
        int[][] result = new int[n][n];
        int loop = 1;

        //转几圈
        while (loop++ <= n/2) {
            int j = starty;
            int i = startx;
            //第一行
            for (; j < n - offset; j++) {
                result[startx][j] = count++;
            }
            //第一列
            for (; i < n - offset; i++) {
                result[i][j] = count++;
            }
            //第二行
            for (; j > starty; j--) {
                result[i][j] = count++;
            }
            //第二列
            for (; i > startx; i--) {
                result[i][j] = count++;
            }
            //对起始位置和偏移量进行处理
            startx++;
            starty++;
            offset++;
        }

        if (n % 2 == 1) {
            result[n / 2][n / 2] = count;
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值