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

Leetcode 977. 有序数组的平方

题目链接:977. 有序数组的平方
文章讲解:代码随想录#977. 有序数组的平方
视频讲解:双指针法经典题目 | LeetCode:977.有序数组的平方

题目描述

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例1

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例2

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

思路

这是一个递增顺序的数组,有正数有负数,对每个元素平方后会发现最小的数在中间,较大的数在两头。
因此,我们想到了使用双指针法,从数组的两头向中间遍历,同时还需要动态构建一个大小为n的数组(分配一段长度为n的内存地址)。
在遍历时一定要注意循环的结束条件,需要遍历所有的元素。
另外,此题也可以使用暴力解法,先对每个元素进行平方运算,再排序。

参考代码

int* sortedSquares(int* nums, int numsSize, int* returnSize) {
    *returnSize = numsSize;
    int left = 0, right = numsSize - 1;
    int idx = numsSize - 1;
    int *ans = (int* )malloc(numsSize * sizeof(int)); // 动态分配numsSize个int类型的地址

    while (left <= right) { // 必须判断=的情况,不然最后的元素会漏掉
        int lefts = nums[left] * nums[left];
        int rights = nums[right] * nums[right];
        if (lefts > rights) {
            ans[idx--] = lefts;
            left++;
        } else {
            ans[idx--] = rights;
            right--;
        }
    }
    return ans;
}

总结

  1. 判断循环时需要考虑left=right的情况,否则会漏掉元素。
  2. 在力扣的题目中,一定要搞清楚函数参数的作用,有些参数是输入型参数,有些参数是输出型参数。

LeetCode 209.长度最小的子数组

题目链接:209.长度最小的子数组
文章讲解:代码随想录#209.长度最小的子数组
视频讲解:拿下滑动窗口! | LeetCode 209 长度最小的子数组

题目描述

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例1

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例2

输入:target = 4, nums = [1,4,4]
输出:1

示例3

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

思路

这是一道经典的滑动窗口的题目,在一个for循环中,循环的索引作为滑动窗口的终止位置,而滑动窗口的起始位置是一个可变的指针,根据条件(元素总和大于等于 target )适时变动,找到最小的子数组。
所以,滑动窗口就是一个不断调节子数组的起始终止位置,从而找到满足条件的最优解。
其实滑动窗口本质就是双指针法,不过双指针在不断调节过种像是一个窗口在移动。

滑动窗口要确定以下三点:

  • 窗口内是什么? – 满足条件(子数组各>=target)的连续子数组
  • 如何移动窗口的起始位置? – 如果窗口内的值>=target,窗口就要向后移动
  • 如何移动窗口的结束位置? – for循环编译中的索引

参考代码

int minSubArrayLen(int target, int* nums, int numsSize) {
    int len = 0;
    int max_magic = numsSize + 1;
    int min = max_magic; // min的初值一定要大于元素个数
    int left = 0, right = 0;
    int sum = 0;

    for (; right < numsSize; right++) {
        sum += nums[right];

        while (sum >= target) {
            len = right - left + 1;
            min = min > len ? len : min;
            sum -= nums[left++];
        }
    }
    // 数组所有元素加起来仍然小于target,则返回0
    return min == max_magic ? 0 : min;
}

总结

  1. 变量min的初始化需要格外注意,大于数组总长即可。
  2. 在返回min时,一定要考虑异常情况,即所以元素加起都小于target,返回0。

59. 螺旋矩阵 II

题目链接:59. 螺旋矩阵 II
文章讲解:代码随想录#59. 螺旋矩阵 II
视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II

题目描述

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例1

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例2

输入:n = 1
输出:[[1]]

思路

可以查看视频讲解,讲解特别清楚,强烈推荐。

参考代码

int** generateMatrix(int n, int* returnSize, int** returnColumnSizes) {
    *returnSize = n;
    *returnColumnSizes = (int *)malloc(n * sizeof(int));

    // 申请一个二维数组array[n][n]
    int **array = NULL;
    array = (int **)malloc(n * sizeof(int*));
    for (int i = 0; i < n; i++) {
        *(array + i) = (int *)malloc(n * sizeof(int));
        (*returnColumnSizes)[i] = n;
    }

    int startX = 0, startY = 0;
    int offset = 1;
    int numb = 1;
    int cnt = n / 2; // 因为是绕圈,对于n,只需要循环n/2
    int x, y;

    // 绕圈时循环边界使用左闭右开
    while (cnt--) { 
        for (y = startY; y < n - offset; y++) {
            array[startX][y] = numb++;
        }
        for (x = startX; x < n - offset; x++) {
            array[x][n - offset] = numb++;
        }
        for (;y > startY; y--) {
            array[x][y] = numb++;
        }
        for (;x > startX; x--) {
            array[x][startY] = numb++;
        }
        startX++;
        startY++;
        offset++;
    }
    if (n % 2 == 1) { // 如果是奇数,则补最中间的元素
        array[startX][startY] = numb;
    }

    return array;
}

总结

  1. 不熟悉动态申请二维数组
  2. 不清楚题目中的第三个参数returnColumnSizes的含义
  3. 理解结束条件
  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值