一、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的开始位置。最后看奇偶在最中间补上最后一个数。