977-有序数组的平方
【分析】
1、题干背景:非递减顺序说明是按照递增排序排列的数组,只不过可能包含相同大小的元素
2、这道题还有个特点,可能包含负数,当负数平方之后的值是可能比之前大的
3、这道题最直接的方法是用一个新的数组存放平方过后的值,再从大到小进行排序
4、这道题的关键问题在于我们没有办法判断负值放在哪?所以是否可以考虑归并算法的插值处理?
【疑问】
1、如果是O(n*n(logn))复杂度如何实现?
只需要一个循环+一个排序即可解决
nums.map((item) => Math.pow(item, 2)).sort((a, b) => a - b);
2、如果是O(n)复杂度如何实现?
由于已经是排序了的数组了,所以可以依靠双指针来进行两个数的比较(负数越小,平方之后越大,所以不用考虑负数平方相互之间大小会乱的情况)
这个思想其实和归并排序的“并”思想是一样的
【代码实现】
const list = [];
let startIndex = 0;
let endIndex = nums.length - 1;
while (startIndex <= endIndex) {
const startNum = nums[startIndex] * nums[startIndex];
const endNum = nums[endIndex] * nums[endIndex];
if (startNum < endNum) {
// 说明起始索引的数更小,取较大的数
list.unshift(endNum);
endIndex--;
} else {
list.unshift(startNum);
startIndex++;
}
}
return list;
209-长度最小的子数组
【分析】
1、题干背景:要求满足条件的子数组的最小长度,所以一定有个大小比较
2、只要>=target均满足,所以当前要实现最小长度一定是total<target,但是total+curNum>=target,这个时候才是最小的
3、优先想到的是暴力解法,只不过复杂度是O(n*n)
4、可以使用滑动窗口来处理这个逻辑
【疑问】
1、滑动窗口的起始索引是什么?
startIndex最初是从索引0开始的,但是当total满足>=target的时候,就可以考虑缩小窗口了,也就是startIndex--。
2、滑动窗口的结束索引是什么?
endIndex最初也是从索引0开始的,当total<target的时候,就应该扩大窗口。
3、如何取最小长度呢?
最小长度的初始值为Infinity,这样才可以用Math.min来取较小值
最小长度一定是满足total>=target且endIndex-startIndex+1要比之前统计的都要小
这里由于是统计的长度,所以需要在endIndex-startIndex+1执行+1操作
最后返回的时候,根据题意如果不存在则返回0,所以需要判断最小长度是否值仍然为Infinity,如果是则说明不满足total>=target的情况
【代码实现】
let startIdex = 0;
let endIndex = 0;
let total = 0;
let minLength = Infinity;
while (endIndex < nums.length) {
total += nums[endIndex];
while (total >= target) {
// 说明已经超过target了,这个时候可以考虑缩小窗口了
minLength = Math.min(minLength, endIndex - startIdex + 1);
total -= nums[startIdex];
startIdex++;
}
endIndex++; //当和小于目标值的时候,应该往右移动窗口了
}
return minLength === Infinity ? 0 : minLength;
59-螺旋矩阵II
【分析】
1、题干背景:需要螺旋状去填充1~n*n的数
2、它的规律在于都是上右下左这样的循环往复,但是每条边的个数如何计算
【疑问】
1、每边的循环如何模拟?
通过四个for循环来模拟每条边的填数情况,只不过需要借助offset变量来表示每条边的结束位置在哪
2、循环的层数如何确定?
由于每一圈都是对称的,所以n行的矩阵,其可以围绕的圈数为Math.floor(n/2)
3、如何取最小长度呢?
最小长度的初始值为Infinity,这样才可以用Math.min来取较小值
【代码实现】
const ans = new Array(n).fill(0).map((ele) => new Array(n).fill(0));
let startX = 0;
let startY = 0;
let loop = Math.floor(n / 2);
let middle = Math.floor(n / 2);
let offset = 1;
let count = 1;
let i, j;
while (loop--) {
for (j = startY; j < n - offset; j++) {
ans[startX][j] = count++;
}
for (i = startX; i < n - offset; i++) {
ans[i][j] = count++;
}
for (; j > startY; j--) {
ans[i][j] = count++;
}
for (; i > startX; i--) {
ans[i][j] = count++;
}
startX++;
startY++;
offset++;
}
if (n % 2 === 1) {
ans[middle][middle] = count++;
}
return ans;
[todo]螺旋矩阵还需要加深印象和消化,虽然这个逻辑只是在模拟顺时针填充的过程,但是很容易绕晕