算法打卡day02|977有序数组平方|209长度最小的子数组|59螺旋矩阵II|JavaScript

72 阅读4分钟

LeetCode 977.有序数组平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

  • 思路
    • 法1:遍历,每个平方,去重,排序。这样做非常不优雅,并且还会被追问数组API的内核,比如... (js数组去重
      • 👨‍面试官:说说sort方法是用的什么排序算法?
      • 😀你:sort()底层由引擎底层实现,如果是稳定排序,一般是timsort(归并排序和插入排序的混合排序算法),如果不稳定,一般是快排。sort 函数默认按 ASCII 排序,所以直接排数字是字典序。(还好大概了解了一下,虽然不多
      • 👨‍面试官:快排的时间复杂度?归并呢?
      • 😏你:快排最好O(nlogn),归并O(nlogn)。(小样儿,还不迷死你~
      • 👩‍面试官:写个快排吧~(看你得瑟
      • 🤡你:卒...
    • 法2:因为是有序数组,所以双指针,从两边向中间收束,并且因为有JS的特有unshift数组API,可以直接实现每次在答案数组头部插入当前较大平方值。
      • 问:没有unshift的语言怎么办?
      • 答:数组倒插,即:初始化全0数组,下标从最后一个开始,每更新一个,i -= 1
  • 注意点:为什么是头插法?那不是倒序了吗?每次插入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循环,至于是表示窗口的左边界还是右边界,请按照以上几个问题问自己一遍。其次就是如何保存最短子数组长度,首先初始化为一个极大值(自不用说),其次就是每次更新时取最小值。
/**
 * @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 。

  • 思路:模拟,遇到这样的题目也只能模拟了,用代码把流程走一遍。 image.png
  • 注意点:
    • 区间边界值处理,做到每个区间的开闭是一样的,不能取重复了,比如(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;
};

总结

总结的部分,我觉得代码随想录的数组总结部分就写得很好很全面了。链接在此