【算法】代码随想录训练营Day2打卡,LeetCode 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II

本文介绍了在LeetCode训练营中解决三个算法问题的方法,包括有序数组的平方的C语言和JS解法,使用双指针法避免排序;长度最小的子数组问题,利用快慢指针实现滑动窗口;以及螺旋矩阵II的构建,通过迭代方式按螺旋顺序填充矩阵。作者强调了画图和理解数据结构在解题过程中的重要性。

【算法】代码随想录训练营Day2打卡,LeetCode 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II

数组

代码随想录算法训练营Day2任务。

  1. LeetCode 977.有序数组的平方
  2. LeetCode 209.长度最小的子数组
  3. LeetCode 59.螺旋矩阵II

LeetCode 977.有序数组的平方

力扣链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

这道题我们读题, 首先数组是非递减序,要求将数组每一项平方后,再按照非递减序排列。

首先关键词就是数组是非递减序,那么就可以理解为 有序递增 , 而这一道题要求返回的是平方后的非递减序数组,那么我们就要考虑到负数的问题了。

首先这道题最无脑最简单的解法就是循环暴力解啦,我们将每一个数都平方之后再进行排序,这样就完美解决了这个问题,但是暴力解这种方法肯定不是这道题考察的点,他的时间复杂度也更高是O(n+nlogn)

所以我们就要思考是否右更优的解法呢,那么我们可以考虑一下数组中最常用的双指针法,这道题的重点在于负数的平方是正数,可能比某个正数更大,那么快慢指针的双指针法明显是不适用的。
如图

如图我们发现如果使用快慢指针,我们无法快速判断-5的平方和 7 3的平方谁更大,那么怎么能够直接比较呢?看着图我们脑袋灵光一闪,使用首尾指针就可以快速判断,然后我们使用一个新的长度一致的数组用尾插法进行填充。
如图
在这里插入图片描述
以此类推 循环条件为 left<=right,当左右指针撞再一起之后结束循环

思路讲完了就来看看代码把

C语言解法

双指针法

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    int* res = (int*)malloc(sizeof(int) * numsSize); // 创建一个相同长度的数组;
    *returnSize = numsSize;
    int left =0;
    int right = numsSize-1;
    int rt=numsSize-1;
    while(left<=right){
        if(abs(nums[left])<abs(nums[right])){
            res[rt--] = nums[right] * nums[right];
            right--;
        }
        else{
            res[rt--] = nums[left] * nums[left];
            left++;
        }
    }
    return res;
}

JS解法

  1. 暴力解
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
    let res = [];
    for(let i=0;i<nums.length;i++){
        res[i] = nums[i] * nums[i];
    }
    res.sort((a,b)=> a-b);
    return res 
};
  1. 双指针法
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
    let res = [];
    let left = 0 ;
    let right = nums.length-1;
    let cur = nums.length -1 ;
    while(left<=right){
        if(Math.abs(nums[left])<Math.abs(nums[right])){
            res[cur--] = nums[right] * nums[right];
            right--;
        }else{
            res[cur--] = nums[left]* nums[left];
            left++
        }
    }
    return res 
};

209. 长度最小的子数组

力扣链接:https://leetcode.cn/problems/minimum-size-subarray-sum/description/

首先我们读题
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。
这道题显而易见可以使用快慢指针来代表我们连续子数组的边界(这种方法也叫滑动窗口)
接下来我们来梳理一下思路。
就用题中的案例 target = 7, nums = [2,3,1,2,4,3]
既然是双指针,那么我们就要先定义一个slot,一个fast 两个指针,并指向0 ,需要一个sum变量来计算我们连续子数组的和,需要一个res来记录我们的最小的子数组的长度,最后返回的也是这个res

我们需要一个循环条件,这个条件则是fast指针要<数组nums的长度,因为是子数组,所以你子数组的右边界是一定不能长于nums数组的右边界的,所以这里的循环条件是 fast<nums.length是很好理解的

而我们将sum的值初始化为数组的第0项 即 sum = nums[0];
因为我们一进入循环体就要判断sum的值;

当sum<target的时候,我们就需要把 fast指针向后移动 且 sum要加上 fast移动后所指的值

当sum>= target的时候 因为我们要寻求最小的子数组长度,所以我们要把slot指针向后移动来缩小边界,所以 slot++ 且 sum要减去slot移动后所指向的值,且 res要取 res所存的值与 当前子数组的长度之中的最小值。

如此到循环结束 我们返回的res就是满足条件的最小连续子数组的长度了

以上解析可根据下图理解

在这里插入图片描述

接下来思路理解完毕,我们就要来写代码了

C语言解法

int minSubArrayLen(int target, int* nums, int numsSize){
    int res = INT_MAX;
    int slot =0;
    int fast =0;
    int sum = nums[0];
    while(fast<numsSize){
    
        if(sum<target ){
            fast++;
            if(fast<numsSize){ //这里要注意,如果越界取值会报错,所以在这里判断一下是否越界 坑!!
                sum += nums[fast];
            }
        }else{
            int curSize = fast-slot+1;
            res = res>=curSize ? curSize : res ;
            sum -= nums[slot++];
        }
    }
    return res == INT_MAX ? 0 : res;
}

JS解法

/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
    let res = Infinity;
    let slot =0;
    let fast =0;
    let sum = nums[0];
    while(fast<nums.length){
        if(sum<target){
            sum += nums[++fast];
        }else{
            res = Math.min(res,fast-slot+1)
            sum -= nums[slot++];// 注意slot++一定要放在 计算数组长度的后面哦!
        }
    }
    return res == Infinity ? 0 : res;
};

59. 螺旋矩阵 II

https://leetcode.cn/problems/spiral-matrix-ii/

根据题目来梳理思路,首先我们要做一个n*n的二维数组,
接下来我们要螺旋填入数字1-n^2

那么我们以n=4为例子 画一张图,如果想要有规律的填充就要做到以下的事情
在这里插入图片描述

C语言解法

int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
    //初始化返回的结果数组的大小
    *returnSize = n;
    *returnColumnSizes = (int*)malloc(sizeof(int) * n);
    //初始化返回结果数组ans
    int** ans = (int**)malloc(sizeof(int*) * n);
    int i;
    for(i = 0; i < n; i++) {
        ans[i] = (int*)malloc(sizeof(int) * n);
        (*returnColumnSizes)[i] = n;
    }
    int startX = 0;
    int startY = 0;
    int mid = n / 2;
    int loop = n / 2;
    int offset = 1;
    int count = 1;

    while(loop) {
        int col = startX;
        int row= startY;

        for(; col< startX+ n - offset; col++) {
            ans[row][col] = count++;
        }

        for(; row < startY+ n - offset; i=row++) {
            ans[row][col] = count++;
        }

        for(; col > startY; col--) {
            ans[row][col] = count++;

        for(; row > startX; row--) {
            ans[row][col] = count++;
        }
        offset+=2;
        startX++;
        startY++;
        loop--;
    }
    if(n%2)
        ans[mid][mid] = count;

    return ans;
}

JS解法

/**
 * @param {number} n
 * @return {number[][]}
 */
var generateMatrix = function(n) {

    let translate = 1;
    let startX = startY = 0; //其实位置
    let cont = 1 ;
    let loop = Math.floor(n/2);
    let mid = Math.floor(n/2);
    let res = new Array(n).fill(0).map(() => new Array(n).fill(0));

    while(loop--){

        let row = startY ; 
        let col = startX ;

        for(;col<startX+n-translate;col++){
            res[row][col] = cont++
        }

        for(;row<startY + n - translate;row++){
            res[row][col] = cont++
        }

        for(;col>startX;col--){
            res[row][col] = cont++
        }

        for(;row>startY;row--){
            res[row][col] = cont++
        }

        startX++;
        startY++;
        translate+=2;
    }

    if(n%2==1){
        res[mid][mid] = cont
    }
    return res;
};

今日心得

今日完成算法+完成文章的总共时间共3小时,其中长度最小的子数组是印象最深刻的,在自己写的过程中,也通过画图来梳理自己的思路,然后根据画的图来写代码会少走很多弯路,所以我认为这个是一个很好的过程。

数组

对于数组这一块,我在day1时总结了我对数组这个数据结构的基本理解和 我对于JS和c语言中数组的区别的概念。同样的在刷题过程中我也能很明确的感知到脚本语言JS与编译语言C的巨大化的差异,C语言十分的严谨,甚至数组在寻址过程中产生越界会报错,而js只会指向null 并不会报错,所以js在写题的时候有些地方会很偷懒,不用特别严谨。但再用c去复刻js的代码时,就会出现很多问题,在这里也踩过很多坑。
而数组中,我们最常用的就是指针法,快慢指针,滑动窗口,相对指针等等,根据题意思和一些例子,我们通过画图可以快速的决定我们是用哪一种指针法

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值