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

77 阅读3分钟

977-有序数组的平方

题目链接

【分析】

1、题干背景:非递减顺序说明是按照递增排序排列的数组,只不过可能包含相同大小的元素

2、这道题还有个特点,可能包含负数,当负数平方之后的值是可能比之前大的

3、这道题最直接的方法是用一个新的数组存放平方过后的值,再从大到小进行排序

4、这道题的关键问题在于我们没有办法判断负值放在哪?所以是否可以考虑归并算法的插值处理?

【疑问】
1、如果是O(n*n(logn))复杂度如何实现?

只需要一个循环+一个排序即可解决

nums.map((item) => Math.pow(item, 2)).sort((a, b) => a - b);

2、如果是O(n)复杂度如何实现?

由于已经是排序了的数组了,所以可以依靠双指针来进行两个数的比较(负数越小,平方之后越大,所以不用考虑负数平方相互之间大小会乱的情况)

这个思想其实和归并排序的“并”思想是一样的

【代码实现】
  const list = [];
  let startIndex = 0;
  let endIndex = nums.length - 1;
  while (startIndex <= endIndex) {
    const startNum = nums[startIndex] * nums[startIndex];
    const endNum = nums[endIndex] * nums[endIndex];
    if (startNum < endNum) {
      // 说明起始索引的数更小,取较大的数
      list.unshift(endNum);
      endIndex--;
    } else {
      list.unshift(startNum);
      startIndex++;
    }
  }
  return list;

209-长度最小的子数组

题目链接

【分析】

1、题干背景:要求满足条件的子数组的最小长度,所以一定有个大小比较

2、只要>=target均满足,所以当前要实现最小长度一定是total<target,但是total+curNum>=target,这个时候才是最小的

3、优先想到的是暴力解法,只不过复杂度是O(n*n)

4、可以使用滑动窗口来处理这个逻辑

【疑问】
1、滑动窗口的起始索引是什么?

startIndex最初是从索引0开始的,但是当total满足>=target的时候,就可以考虑缩小窗口了,也就是startIndex--。

2、滑动窗口的结束索引是什么?

endIndex最初也是从索引0开始的,当total<target的时候,就应该扩大窗口。

3、如何取最小长度呢?

最小长度的初始值为Infinity,这样才可以用Math.min来取较小值

最小长度一定是满足total>=target且endIndex-startIndex+1要比之前统计的都要小

这里由于是统计的长度,所以需要在endIndex-startIndex+1执行+1操作

最后返回的时候,根据题意如果不存在则返回0,所以需要判断最小长度是否值仍然为Infinity,如果是则说明不满足total>=target的情况

【代码实现】
  let startIdex = 0;
  let endIndex = 0;
  let total = 0;
  let minLength = Infinity;
  while (endIndex < nums.length) {
    total += nums[endIndex];
    while (total >= target) {
      // 说明已经超过target了,这个时候可以考虑缩小窗口了
      minLength = Math.min(minLength, endIndex - startIdex + 1);
      total -= nums[startIdex];
      startIdex++;
    }
    endIndex++; //当和小于目标值的时候,应该往右移动窗口了
  }
  return minLength === Infinity ? 0 : minLength;

59-螺旋矩阵II

题目链接

【分析】

1、题干背景:需要螺旋状去填充1~n*n的数

2、它的规律在于都是上右下左这样的循环往复,但是每条边的个数如何计算

【疑问】
1、每边的循环如何模拟?

通过四个for循环来模拟每条边的填数情况,只不过需要借助offset变量来表示每条边的结束位置在哪

2、循环的层数如何确定?

由于每一圈都是对称的,所以n行的矩阵,其可以围绕的圈数为Math.floor(n/2)

3、如何取最小长度呢?

最小长度的初始值为Infinity,这样才可以用Math.min来取较小值

【代码实现】
  const ans = new Array(n).fill(0).map((ele) => new Array(n).fill(0));
  let startX = 0;
  let startY = 0;
  let loop = Math.floor(n / 2);
  let middle = Math.floor(n / 2);
  let offset = 1;
  let count = 1;
  let i, j;

  while (loop--) {
    for (j = startY; j < n - offset; j++) {
      ans[startX][j] = count++;
    }
    for (i = startX; i < n - offset; i++) {
      ans[i][j] = count++;
    }
    for (; j > startY; j--) {
      ans[i][j] = count++;
    }
    for (; i > startX; i--) {
      ans[i][j] = count++;
    }
    startX++;
    startY++;
    offset++;
  }
  if (n % 2 === 1) {
    ans[middle][middle] = count++;
  }
  return ans;

[todo]螺旋矩阵还需要加深印象和消化,虽然这个逻辑只是在模拟顺时针填充的过程,但是很容易绕晕