[算法训练营 Day 2] LC 977,209,59

122 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情

题目

有序数组的平方

题目:977. 有序数组的平方 - 力扣(LeetCode)

题解:

  1. 暴力解

    平方+排序

    我们可以利用map进行遍历,将每个数都平方,然后利用sort在排序

    因为题目并没有要求我们原地修改啥的,所以我觉得是可以使用额外空间的

  2. 双指针

    其实我们每一次判断最大值,只需要判断某个范围内的头和尾谁更大就好了,找到最大值以后收缩范围。

代码:

  1. 暴力
function sortedSquares(nums: number[]): number[] {
    const newnums = nums.map((value, index) => Math.pow(value, 2))
    newnums.sort((a, b) => a - b)
    return newnums
};
  1. 双指针
function sortedSquares(nums: number[]): number[] {
  // 双指针解法
  let left = 0;
  let right = nums.length - 1;
  const newnums = new Array(nums.length);
  let index = newnums.length - 1;
  while (left <= right) {
    let leftVal = Math.pow(Math.abs(nums[left]), 2);
    let rightVal = Math.pow(Math.abs(nums[right]), 2);
    if (leftVal>=rightVal) {
      // 左边的值大
      newnums[index--] = leftVal;
      left++;
    } else {
      // 右边的值大
      newnums[index--] = rightVal;
      right--;
    }
  }
  return newnums;
};

长度最小的子数组

题目:209. 长度最小的子数组 - 力扣(LeetCode)

题解:

其实这道题很明显就是使用滑动窗口,滑动窗口就是在一个区间里面去调节区间大小。这边我们就是要在这个数组上去寻找长度最小的>= target

我们一般都会将滑动窗口设置为[0,0),因为这样的话,里面就不会由遗漏的值,但是其实你也可以设置[],()都是可以的。

我们首先先让窗口扩大,直到sum已经>=target.

这时候需要缩小窗口left++

需要注意的是,当你缩小串口的时候,也就意味着,你的一些原来的值是会发生变化的sum,len

当收缩到不再满足条件的时候,我们就需要扩大窗口,就这样一直进行,直到不在满足条件。

那么我们只需要明确什么时候需要收缩?

当我们当前区间里面的和sum>target时,我们就可以进行收缩了

东哥说过,滑动窗口需要考虑几个问题:

  1. 什么时候扩大窗口,扩大以后需要更新哪些数据?
  2. 什么时候停止扩大,缩小窗口,需要更新哪些数据?
  3. 结果应该在扩大窗口时更新还是在缩小窗口时获取?

参考:我写了首诗,把滑动窗口算法变成了默写题 :: labuladong的算法小抄 (gitee.io)

代码:

function minSubArrayLen(target: number, nums: number[]): number {
    // 设置两个指针
    let left = 0;
    let right = 0;
    let sum = 0;
    let len = Number.MAX_VALUE;
    while (right < nums.length) {
        sum += nums[right]
        right++;
        while (sum >= target) {
            // 那么开始收缩
            len = Math.min(len,right-left)
            sum -= nums[left];
            left++
        }
    }
    return len === Number.MAX_VALUE ? 0 : len

};

螺旋矩阵2

题目:59. 螺旋矩阵 II - 力扣(LeetCode)

题解:

其实拿到这道题目的时候我没有任何思路,我对模拟题真的不得章法啊。

其实我们是一圈一圈进行遍历,遵守左闭右开原则

为什么是左闭右开呢?

因为我们其实遍历的时候,需要特别注意四个角的值,我们设置为左闭右开的时候,其实也就表明了,右边的角都留给了另一个边。

代码:

function generateMatrix(n: number): number[][] {
  // 模拟,每次都是左闭右开
  let loop = Math.floor(n / 2);
  let startx = 0;
  let starty = 0;
  let offset = 1;
  let num = 1;
  let matrix: number[][] = new Array(n).fill(0).map(() => new Array(n).fill(0));

  while (loop) {
    let i = startx;
    let j = starty;
    for (; j < n - offset; j++) {
      matrix[i][j] = num++;
    }
    for (; i < n - offset; i++) {
      matrix[i][j] = num++;
    }
    for (; j > starty; j--) {
      matrix[i][j] = num++;
    }
    for (; i > startx; i--) {
      matrix[i][j] = num++;
    }
    startx++;
    starty++;
    offset++;
    loop--;
  }
  if (n % 2) {
    // 奇数
    matrix[startx][starty] = Math.pow(n, 2);
  }
  return matrix;
}