LeetCode 977.有序数组平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
- 思路
- 法1:遍历,每个平方,去重,排序。这样做非常不优雅,并且还会被追问数组API的内核,比如... (js数组去重)
- 👨面试官:说说
sort方法是用的什么排序算法? - 😀你:
sort()底层由引擎底层实现,如果是稳定排序,一般是timsort(归并排序和插入排序的混合排序算法),如果不稳定,一般是快排。sort函数默认按ASCII排序,所以直接排数字是字典序。(还好大概了解了一下,虽然不多 - 👨面试官:快排的时间复杂度?归并呢?
- 😏你:快排最好
O(nlogn),归并O(nlogn)。(小样儿,还不迷死你~ - 👩面试官:写个快排吧~(看你得瑟
- 🤡你:卒...
- 👨面试官:说说
- 法2:因为是有序数组,所以双指针,从两边向中间收束,并且因为有JS的特有
unshift数组API,可以直接实现每次在答案数组头部插入当前较大平方值。- 问:没有
unshift的语言怎么办? - 答:数组倒插,即:初始化全0数组,下标从最后一个开始,每更新一个,
i -= 1。
- 问:没有
- 法1:遍历,每个平方,去重,排序。这样做非常不优雅,并且还会被追问数组API的内核,比如... (js数组去重)
- 注意点:为什么是头插法?那不是倒序了吗?每次插入left和right中绝对值较大的一个的平方值,后续再有数据更新,之前的会后移。
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
let ans = [];
let left = 0;
let right = nums.length - 1;
while(left <= right){
if(Math.abs(nums[left]) >= Math.abs(nums[right])){
// 较大数字的插入答案数组
// js特有数组API,头插
ans.unshift(nums[left]*nums[left]);
left += 1;
}else{
ans.unshift(nums[right]*nums[right]);
right -= 1;
}
}
return ans;
};
LeetCode 209.长度最小的子数组
给定一个含有 n个正整数的数组和一个正整数 target。
找出该数组中满足其和 ≥ target的长度最小的连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
- 思路:
- 法1:暴力双层for循环。虽然有一点滑动窗口的意思在里面,但是会超时。
- 法2:滑动窗口。
- 滑动窗口的for循环表示哪个界限?
- 表示左边界?那如何判断窗口内的和是
>=target的呢?是不是还需要一层for循环来框住几个数字? - 表示右边界?答对了,在右边界延伸的过程中就计算窗口内数值之和,一旦
>=target了,就开始收缩。
- 表示左边界?那如何判断窗口内的和是
- 滑动窗口的for循环表示哪个界限?
- 注意点:滑动窗口里面也有一层for循环,至于是表示窗口的左边界还是右边界,请按照以上几个问题问自己一遍。其次就是如何保存最短子数组长度,首先初始化为一个极大值(自不用说),其次就是每次更新时取最小值。
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
let left = 0, right = 0;
let sum = 0;
let ans = nums.length + 1; // 也可以取一个极大数,这里直接取数组长度+1,因为子数组长度不可能大于数组长度的
for(; right < nums.length; right ++){
sum += nums[right];
while(sum >= target){
ans = Math.min(ans, right - left + 1); // 先记录当时数组长度
sum -= nums[left];
left += 1;
}
}
return ans === nums.length + 1 ? 0 : ans;
};
LeetCode 59.螺旋矩阵II
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
- 思路:模拟,遇到这样的题目也只能模拟了,用代码把流程走一遍。
- 注意点:
- 区间边界值处理,做到每个区间的开闭是一样的,不能取重复了,比如(1,2],(2,3]这样的。
- 偏移量的设置,偏移量的存在,也就关系到边界值的处理。
- 圈数,循环几圈,n分奇偶,奇数有个中心,偶数没有。
- 每次模拟时,哪个坐标在变,哪个是固定的。
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function(n) {
// 初始化一个n x n的二维数组
let matrix = new Array(n).fill(0).map(() => new Array(n).fill(0));
let offset = 1;
let startX = 0, startY = 0;
let mid = Math.floor(n/2);
let count = 1;
let loop = Math.floor(n / 2); // 圈数
while(loop >= 0){
for(let i = startY; i < n - offset; i ++){ // ①
matrix[startX][i] = count;
count += 1;
}
for(let i = startX; i < n - offset; i ++){ // ②
matrix[i][n - offset] = count;
count += 1;
}
for(let i = n - offset; i > startY; i --){ // ③
matrix[n - offset][i] = count;
count += 1;
}
for(let i = n - offset; i > startY; i--){ // ④
matrix[i][startY] = count;
count += 1;
}
offset += 1;
startX += 1;
startY += 1;
loop -= 1;
}
if( n % 2 === 1){
matrix[mid][mid] = count;
}
return matrix;
};
总结
总结的部分,我觉得代码随想录的数组总结部分就写得很好很全面了。链接在此