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

110 阅读4分钟

977.有序数组的平方

我的解题思路

我的解题思路目前还是局限在使用库函数:

  1. 先使用map方法,对数组的每一个操作进行平方处理
  2. 使用sort排序。其实就可以扪心自问一下,sort底层原理是真的懂吗?

补充知识点:

双指针解法

时间复杂度为O(n) ,那么会有一次for循环。要搞清楚到底循环什么!

由于遍历数组,还是从两边遍历,所以这次的指针和之前的快慢指针还是有区别的。for循环中定义两个变量i, j(i = 0, j = nums.length - 1),用来当做双指针。

思路:

  1. 由于数组的特性是按 非递减顺序 排序的,所以数组元素平方过后,两边肯定是比中间大的。
  2. 先比较最左边和最右边的元素平方后的大小,确定最大值后,倒序放到新数组(长度和原数组一样)中
  3. 如果(nums[i])^2 < (nums[j])^2,那么newArr[k--]中放的就是(nums[j])^2,然后j--便于下一次的比较
  4. 若步骤3不成立,那么(nums[i])^2就有可能大于或许等于(nums[j])^2。那么newArr[k--]中放的就是(nums[i])^2,然后i++ 便于下一次的比较
 /**
  * @param {number[]} nums
  * @return {number[]}
  */
 var sortedSquares = function(nums) {
     // let i = 0, j = nums.length - 1;
     let newArr = [];
     let k = nums.length - 1
     // 核心思路:双指针
     for(let i = 0, j = nums.length - 1;i <= j;) {
         if(nums[i] * nums[i] < nums[j] * nums[j]) {
             newArr[k--] = nums[j] * nums[j];
             j--;
         } else {
             newArr[k--] = nums[i] * nums[i];
             i++;
         }
 ​
     }
     return newArr
 };

以上是我的代码。可以看看其他版本的js写法:

carl.png

209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

来源:力扣(LeetCode) 链接:leetcode.cn/problems/mi…

滑动窗口解法

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

滑动窗口用到了for循环,for(j...),其中i, j是两个指针。那么i和j谁用作起始位置和终止位置是十分重要的。

一个for循环里面的 j ,指向的一定是终止位置。

(重点)如何移动起始位置?

如果说起始位置 i 在下标0那里,先for循环一个个移动终止位置 j (j=0;j<数组长度;j++)。通过 j 不断移动,求出起始和终止的这个区间里面元素相加的和,当和大于等于target时,就收集这个区间的长度。

每一次区间长度得到后,要拿当前的长度值和之前得到的长度值做一个比较,取出最小值。这样就能不断的更新区间的最小值。

⭐️当和大于等于target时用if比较好还是while比较好?

答:用while。因为我们要的是起始位置持续向后移动,以此来更新滑动窗口大小。

什么时候用if,什么时候用while?

  • 当对一个条件进行一次判断时,可以使用if语句。
  • 当对一个条件进行多次判断时,可以使用while语句。

⭐️之前收集到的区间长度存在哪里了?不存起来怎么与现在的做一个比较?

答:在一开始先定义一个变量,存放一个特别大的数字,比如minL=Number.MAX_VALUE 然后再与当前区间的长度做比较。

⭐️求出起始和终止的这个区间里面元素相加的和,怎么个求法?

答:其实在进行for循环的时候,已经开始一步步累加了。

知识点补充:

以下是我的代码,参考文章中可以看到其他语言的相关解法。

 var minSubArrayLen = function(target, nums) {
     let sum = 0;
     let start = 0;
     let result = Number.MAX_VALUE;  // 用于收集区间的长度
     for(let end = 0; end < nums.length; end++) {
         sum += nums[end];
         while(sum >= target) {
             let subL = end - start + 1;  // 当前区间的长度
             result = Math.min(result, subL);
             sum -= nums[start++];
         }
     }
     return result == Number.MAX_VALUE ? 0 : result;
     // return result
 };

59.螺旋矩阵II

螺旋矩阵经常犯的一些毛病:

处理每一条边的时候,其实对节点的的处理规则都是不一样的。

思路:

  1. 需要定义好的变量:

    • startx——控制x轴的坐标
    • starty——控制y轴的坐标
    • loop——控制圈数
    • mid——当n为奇数时,设置矩阵中间的位置。例如n=5,中间位置就是(2, 2)
    • count——用来给矩阵中的每一个空赋值
    • offset——控制每一条边遍历的长度,每次循环右边界收缩一位
    • 二维数组——let res = new Array(n).fill(0).map(() => new Array(n).fill(0));
  2. 输入n,那么会转几圈? 转n/2圈

  3. n是奇数怎么办?n为5时,矩阵中心的数就是25,除了中心的这个数,外面是2圈。

  4. 模拟顺时针画矩阵的过程:

    • 填充上行从左到右
    • 填充右列从上到下
    • 填充下行从右到左
    • 填充左列从下到上

    由外向内一圈一圈这么画下去。

每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来

 /**
  * @param {number} n
  * @return {number[][]}
  */
 var generateMatrix = function(n) {
     let startX = 0, startY = 0;
     let loop = Math.floor(n/2);
     let mid = Math.floor(n/2);
     let count = 1;
     let offset = 1;
     let res = new Array(n).fill(0).map(() => new Array(n).fill(0));
     
     while(loop--) {
         let i = startX; // 横坐标
         let j = startY; // 纵坐标
 ​
         // 左闭右开
         for(; j < startY + n - offset; j++) {
             res[i][j] = count++;
         }
         for(;i < startX + n - offset; i++) {
             res[i][j] = count++;
         }
         for(;j > startY; j--) {
             res[i][j] = count++;
         }
         for(;i > startX; i--) {
             res[i][j] = count++;
         }
 ​
         // 更新起始位置
         startX++;
         startY++;
 ​
         // 更新offset
         offset += 2;
     }
     
     // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
     if(n % 2 == 1) {
         res[mid][mid] = count;
     }
     return res
 };

参考文章