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

977.有序数组的平方
文章讲解: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

209.长度最小的子数组
文章讲解: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

59.螺旋矩阵II
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/

977.有序数组的平方

感悟有两点;

  1. 有序数组,最值只会出现在两端
  2. 双指针大法我觉得不要去记什么情况下去用,而是记住这个方法,拿到题目去试

209.长度最小的子数组

滑动窗口思路

  1. 使用两个指针 𝑙𝑒𝑓𝑡 和 𝑟𝑖𝑔ℎ𝑡 来表示当前窗口的左右边界,初始时都指向数组的起始位置。right的作用是拓展,满足>=target的要求;left的作用是精简,满足最小长度的要求
  2. 移动右指针扩大窗口,直到窗口内的和大于等于 target。
  3. 当窗口内的和大于等于 target 时,记录当前窗口长度并尝试移动左指针缩小窗口,直到窗口内的和小于 target。
  4. 在移动左指针的过程中,更新最小长度。
  5. 重复上述过程,直到右指针遍历完整个数组。

感悟如下:

  1. 遵循卡哥教导,明确变量的含义,且不能改变,所以我打算每个变量定义的时候都加一行注释
  2. 惊喜发现这个和昨天题目一样,也是同向双指针,因此可以用昨天的方法,跑得快的right遍历数组作为主流程。
public class Array_209_MinimumSizeSubarraySum {
    public int minSubArrayLen(int target, int[] nums) {
        // minLength: 记录了当前满足要求的子串的最短长度
        // total:表示当前子串的
        // left表示找到的最短子串的左边界,right表示找到的最短子串的右边界
        // 子串的范围是[left, right]

        int minLength = Integer.MAX_VALUE;
        int total = 0;
        int left = 0;
        int right = 0;

        for (right = 0; right < nums.length; right++) {
            total += nums[right];
            if (total < target) {
                continue;
            } else {
                while (total >= target) {
                    total -= nums[left];
                    left++;
                }
                left--;
                total += nums[left];
                int tempLength = right - left + 1;
                minLength = Math.min(minLength, tempLength);
            }
        }
        if (minLength == Integer.MAX_VALUE) return 0;
        return minLength;
    }
}

59. 螺旋矩阵 II

卡哥说的没错,这道题确实不考算法,考的是细心还有一点数列求和的数学知识

我拿到这道题,觉得整体去考虑很复杂,就想着能不能把它分解成某些基本操作。然后我发现对于n为偶数的矩形,可以把一个矩形分成很多层,螺旋填充矩阵的过程可以变成一层一层填充矩阵的过程;对于n为奇数的矩形,就是多了填一个中心的操作。
确定好这个基本操作后,我就思考完成这个操作需要哪些数据。思考一下我觉得需要这些数据:

  1. 这一层的起始坐标
  2. 这一层第一个要填充的值
  3. 这一层的宽度

然后就是一个找规律的过程,具体过程我放在下面

Screenshot_20240523_235442.jpg

Screenshot_20240523_235459.jpg

具体代码如下:

limit代表这个东西

image-20240524000820759

public class Array_59_SpiralMatrixII {
    public int[][] generateMatrix(int n) {
        int[][] ans = new int[n][n];
        if (n % 2 == 1) {
            ans[(n - 1) / 2][(n - 1) / 2] = n * n;
        }

        // first代表要填充的那一层的左上角的坐标
        // last代表要填充的那一层的右下角的坐标
        // (因为每一层的左上和右下的横纵坐标都相等,所以传进去一个就行)
        int first = 0;
        int last = n - 1;

        while (first < last) {
            fillLayer(first, last, n, ans);
            first++;
            last--;
        }
        return ans;
    }

    // 这个函数的作用是填充一层。注意,在设计的时候没有把单一的一个元素看做一层
    public  static void fillLayer(int first, int last, int n, int[][] ans) {
        //        System.out.println("此时填充" + String.format("[%d,%d] -- [%d,%d]",first,first,last,last));
        // limit的含义还是看图吧
        int limit = last - first;
        // num 是要填充的第一个值
        int num = 4 * first * n - 4 * first * first + 1;
        // x代表准备填充数据的二维坐标中的第一维,y是第二维
        int x = first;
        int y = first;

        // 开始顺时针填充
        // 填充第一条,即上侧
        for (int i = 0; i < limit; i++) {
            ans[x][y] = num;
            y++;
            num++;
        }
        // 填充第二条,即右侧
        for (int i = 0; i < limit; i++) {
            ans[x][y] = num;
            x++;
            num++;
        }
        // 填充第三条,即下侧
        for (int i = 0; i < limit; i++) {
            ans[x][y] = num;
            y--;
            num++;
        }
        // 填充第四条,即左侧
        for (int i = 0; i < limit; i++) {
            ans[x][y] = num;
            x--;
            num++;
        }
    }

    public static void main(String[] args) {
        Array_59_SpiralMatrixII array_59_spiralMatrixII = new Array_59_SpiralMatrixII();
        array_59_spiralMatrixII.generateMatrix(3);

    }
}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值