代码随想录算法训练营第二天|977.有序数组的平方、206.长度最小的子数组、59.螺旋矩阵II「数组」

227 阅读4分钟

977.有序数组的平方

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

思路
只能想到暴力解法,先平方后排序。

代码

var sortedSquares = function(nums) {
    const newNums = nums.map(el=>el*el)
    function stb (a,b) {
        return a-b
    }
    newNums.sort(stb)
    return newNums
};

优化:

看了文章的双指针解法思路:因为原数组是有序排列的,但是因为要平方,所以不确定负数和正数的平方值大小,因此在原数组头尾分别添加一个指针,比较平方后大小按顺序放入新数组中。

代码

// 自己写
var sortedSquares = function (nums) {
  const newNums = new Array(nums.length)
  let i = 0, j = nums.length - 1, k = nums.length-1
  while (k >= 0) {
    if (nums[i] * nums[i] < nums[j] * nums[j]) {
      newNums[k--] = nums[j] * nums[j]
      j--
    } else {
      newNums[k--] = nums[i] * nums[i]
      i++
    }
  }
  return newNums
};

// 看大佬
var sortedSquares = function(nums) {
    let n = nums.length;
    let res = new Array(n).fill(0);
    let i = 0, j = n - 1, k = n - 1;
    while (i <= j) {
        let left = nums[i] * nums[i],
            right = nums[j] * nums[j];
        if (left < right) {
            res[k--] = right;
            j--;
        } else {
            res[k--] = left;
            i++;
        }
    }
    return res;
};

总结:

当要求时间复杂度为 O(n) 或者原地修改数组的时候可以使用双指针法,即本来需要两次循环完成的操作,通过双指针法一次循环解决问题。

209.长度最小的子数组

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

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

思路
设置两个指针,第一个指针遍历数组中的每一个值,第二个指针动态遍历,计算出每次第一个指针所指的值到第二个指针所指的值的累加和,和目标值进行比较,如果大于等于目标值就对当前子数组长度进行比较,如果小于上一个子数组长度就记录该值,子数组长度初始值是数组长度。
同时对两种情况分别处理:

  1. 如果数组中所有值的累加和小于目标值直接返回0
  2. 如果数组中单个值的长度大于等于目标值直接返回1

代码自己写的错误代码

var minSubArrayLen = function (target, nums) {
  let min = nums.length
  if (nums.reduce((prev,cur)=>prev+cur)<target) return 0
  for (let i = 0; i < nums.length; i++) {
    if (nums[i]>=target) return 1
    if (i<nums.length-1) {
        for (let j = i; j < nums.length; j++) {
        let index = nums.slice(i, j + 1).reduce((prev, cur) => prev + cur)
        console.log(index)
        if (index >= target) {
            min = (j - i + 1) > min ? min : (j - i + 1)
            break
      }
    }
    }
  }
  return min
};

优化:

看了代码随想录文章才知道自己的思路实际上是双循坏暴力解法,看完移动窗口思路以后仍然写不出正确的代码,于是看了一下大佬的解法。
思路是声明两个指针,第二个指针依次遍历数组中的值,计算出当前窗口内的和,如果窗口内的和大于等于目标值,就取当前窗口长度和初始窗口长度(值为无限)进行比较,取小的那一个,然后将第一个指针向后移一位,窗口内的和减去第一个指针所指的值。最后对窗口长度进行判断,如果是初始设置的无限(即数组内没有窗口的和满足要求)就返回0,否则返回得到的最小窗口的长度。

代码:

var minSubArrayLen = function (target, nums) {
    let sum = 0, subLength = Infinity,i,j
    i=j=0
    while (j<nums.length) {
        sum+=nums[j]
        while (sum>=target){

            subLength = Math.min(subLength,j-i+1)
            sum-=nums[i++]
        }
        j++
    }
    return subLength === Infinity?0:subLength
};

总结:

第一个看完思路仍然写不出的题目,看了大佬的解法,能理解逻辑,并且学到了Infinity这个值,希望自己下次遇到该类问题可以解决。

59.螺旋矩阵II

题目
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

思路
没有思路

代码
写不出来

优化:

看了代码随想录的思路后,还是弄不明白如何判断内层循环的数量,不知道怎么设置循环上限。看了卡哥的视频以后,理解了逻辑,下面给出我的思路。
首先分别设置行和列的起始指针startXstartY为0;设置一个循环层数loop=n/2,如果n为奇数在最后单独在中心填入一个值;设置一个索引index表示当前的循环层数;设置一个填入数字的初始值count=1
设置一个外侧循环,判断条件是当前循环层数index是否小于总循环层数,在循环内部设置一个每层循环要填入的数字个数为n-offsetoffset是当前循环层数index+1。然后设置四次循环,分别将数据填入正方形的四个边。然后将行和列的起始指针+1,将当前层数index+1

代码

var generateMatrix = function (n) {
  const arr = new Array(n).fill(0).map(() => new Array(n).fill(0))
  let startX, startY, index, count = 1, loop = Math.floor(n / 2)
  startX = startY = index = 0
  while (index < loop) {
    let offset = index + 1
    let i = startX, j = startY
    for (; j < n - offset; j++) {
      arr[i][j] = count++
    }
    for (; i < n - offset; i++) {
      arr[i][j] = count++
    }
    for (; j > startY; j--) {
      arr[i][j] = count++
    }
    for (; i > startX; i--) {
      arr[i][j] = count++
    }
    startX++
    startY++
    index++
  }
  if (n % 2 === 1) {
    arr[loop][loop] = n * n
  }
  return arr
};

总结:

这道题理解以后其实不难,但是也是我第一次一点思路也没有的题,一开始觉得直接暴力填入,后来怎么想怎么不对,看完代码随想录左闭右开的思路以后有点感觉,但是上手一写又觉得后面的上限无法设置,但是最后看完视频也确实自己写出来了。

Day2总结:

第二天的题其实不难,但是自己算法能力实在太差,已经要花很长时间去思考,并且已经无法独立写出来,但是我会放平心态,毕竟自己算法基础薄弱,在60天的训练营结束以后,自己也会二刷三刷,希望自己可以拿下算法,对于前端方向的自己来说,掌握这些算法思想为也以后的工作打下的很好的基础。