攻克代码随想录Day2(JavaScript) | 977.有序数组的平方 | 209.长度最小的子数组 | 59. 螺旋矩阵II

一、977.有序数组的平方

有序数组的平方是一道经典的双指针法题,其具体代码如下:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
    let left = 0;
    let right = nums.length - 1;
    let newNums = new Array(nums.length).fill(0);
    for(let i = nums.length - 1;i >=0;i--){
        if((nums[left] ** 2) >= (nums[right] ** 2)){
            newNums[i] = nums[left++] ** 2;
        }
        else{
            newNums[i] = nums[right--] ** 2;
        }
    }
    return newNums;
};

算法原理较为清晰,由于我们原本的数组是非递减的,因此数组在平方后,最大值一定在数组的头部尾部。根据以上条件,只要我们设计两个指向平方数组头部和尾部的两个指针,并将它们指向的数进行比较,将较大者放进新声明的新数组的尾部,同时将指向该数的指针向内移动一格。重复上述动作,直至新数组被填满。

二、209.长度最小的子数组

这题的原理为移动窗口法,但实践起来我遇到了一点小困难。具体代码如下:

/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
    let slow = 0;
    let fast = 0;
    let sum = 0;
    let res = nums.length + 1;
    for(;fast < nums.length;fast++){
        sum += nums[fast];
        while(sum >= target){
            res = res < fast - slow + 1 ? res : fast - slow + 1;
            sum -=nums[slow++];
        }
    }
    
    if(res === nums.length + 1){
        return 0;
    }
    return res;
};

在做该题之前,我的想法是使用移动窗口法,先声明指向数组开头的两个指针,然后通过快指针进行遍历。在遍历的过程中,快指针将指向的值累加至sum,如果sum值大于等于target,则进入while循环进行窗口移动,直至跳出循环。但是这一思想没有考虑到如何判定哪一个窗口是最小的,因此,我根据Carl哥的题解,修改了一下我的算法。

首先,在代码的开头,我多声明了一个res变量,一开始将它赋值为nums.length+1,这意味着res的开始值是比任何窗口的长度都要大的,在for循环内部,当sum的值大于等于target的时候,会将这时候的res值与窗口的大小进行比较,如果res更大则将现在窗口的大小赋值给res,若res值更小则不变。

在代码的最后,我们增加一个if语句来判断sum是否大于等于target过,由于只要经过比较后,res的值肯定是小于nums.length+1的。因此,若res的值等于nums.length+1,那么sum肯定没有大于等于target过的,在这一情况下,我们return0就好。其余情况,就返回我们正常的结果,也就是最小滑动窗口的值res。

三、59. 螺旋矩阵II

移除元素是一道较难的题目,完成这道题目花费我很多时间。具体代码如下:

/**
 * @param {number} n
 * @return {number[][]}
 */
var generateMatrix = function(n) {
    let loop = Math.floor(n/2);
    let offset = 1;
    let startX = 0;
    let startY = 0;
    let mid = Math.floor(n/2);
    let i = 0;
    let j = 0;
    let count = 1;
    let matrix = new Array(n).fill().map(() => new Array(n).fill(0));
    while(loop--){
        i = startX;
        for(j = startY;j < n - offset;j++){
            matrix[i][j] = count++;
        }
        for(;i < n - offset;i++){
            matrix[i][j] = count++;
        }
        for(;j > offset - 1;j--){
            matrix[i][j] = count++;
        }
        for(;i > offset - 1;i--){
            matrix[i][j] = count++;
        }
        startX++;
        startY++;
        offset++
    }
    if(n % 2 === 1){
        matrix[mid][mid] = count;
    }
    return matrix;
};

做这道题前,我们需要首先明白这题的原理是什么。简单地说,该题的原理就是外圈绕完绕内圈,遇到奇数补个中。看似简单,但实践起来所需要的变量非常多。

首先,我们一开始声明的loop是我们进行遍历的圈数,为n/2并向下取整。因此,对于n=2/3,我们遍历1圈,对于n=4/5,我们遍历2圈,以此内推。

offset是一个往内部抵消的值。举个例子,对于n=5的情况,它第一圈为4个循环,每个循环走4步,第二圈则走2步,这不同圈数步数的不同,就体现在offset这边,offset每一圈循环完增加1(体现在循环左右两侧各往里缩一格)。

startX和startY则为每一圈起始的位置,一开始为坐标(0,0),每一圈迭代完增加1,因此第二圈(如有)则为(1,1),以此内推。

mid是当n为奇数时,我们给最中间的值进行填补时使用的。i,j则为在循环中不断变化的坐标,而count就是从1开始不断增加的数,随着循环不断向里面送数。matrix就是一个二维数组

后面的部分就是while循环了,每个循环4个部分进行填数,之后重新调整offset以及x,y的开始位置。最后看奇偶在最中间补上最后一个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值