代码随想录day02

文章介绍了三种编程算法问题的解题思路,包括使用双指针法解决有序数组的平方问题,优化时间复杂度;运用滑动窗口解决寻找长度最小的子数组问题;以及通过控制边界和循环逻辑生成螺旋矩阵。这些方法都展示了高效的算法设计思想。
摘要由CSDN通过智能技术生成

代码随想录day02

977.有序数组的平方

有序数组的平方【简单】

解题思路

数组平方的最大值就在数组的两端.
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

代码

  1. 暴力解法 复杂度O(nlogn)
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
  //先求平方再排序 复杂度O(nlogn)
  nums = nums.map((item => {
    return item*item
  })) 
  return nums.sort((a,b) => (a-b)) //
};

2.双指针法,复杂度O(n)

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
  let len = nums.length
  let k=len-1
  let result = new Array(len).fill(0)
  for(let i=0,j=len-1; i<len&j>=0&i<=j;) {
    if(nums[i]*nums[i] > nums[j]*nums[j]) {
      result[k--] = nums[i]*nums[i]
      i++
    } else {
      result[k--] = nums[j]*nums[j]
      j--
    }
  }
  return result
};

209.长度最小的子数组

长度最小的子数组【中等】

解题思路–滑动窗口

1.使用滑动窗口来解决使用一个for循环解决两个for循环的事情,本质上也是使用两个指针。
2.只用一个指针j,代表的是终止位置(注意不是起始位置)
3.起始位置需要用一个动态移动的策略来移动位置

代码

  1. 暴力解法 复杂度O(n^2),超时了不行!!
/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
  let result = Infinity;
  for(let i=0;i<nums.length;i++) {
    for(let j=i;j<nums.length;j++) {
      let count = 0
      for(let p=i; p<=j; p++) {
        count += nums[p]
      }
      if(count >= target) {
        result = Math.min(result,j-i+1)
      }
    }
  }
  return result===Infinity ? 0 : result 
};

2.滑动窗口,复杂度O(n)

/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
  let result = Infinity;
  let i=0 // 滑动窗口起始位置
  let sum=0 // 滑动窗口数值之和
  let subLength=0 // 滑动窗口的长度
  for(let j=0;j<nums.length;j++) {
    sum += nums[j] 
    // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
    while(sum >= target) {
      subLength = j-i+1 // 取子序列的长度
      sum -= nums[i++]
      result = Math.min(result,subLength) // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
    }
  }
  // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
  return result===Infinity ? 0 : result
};

重点和收获

1.所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果,用一个for循环来做2个for循环所做的事情。
2.滑动窗口解题的关键:窗口的起始位置如何移动?
就是当我们发现集合里面所有的元素和 >= target,我们再去移动起始位置,这样就实现了动态调整起始位置,来去收集不同长度区间里面的和。

59.螺旋矩阵

螺旋矩阵【中等】

解题思路

1.本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
2.注意节点的边界处理,坚持左闭右开的原则
3.首先确定每个循环转几圈呢?n/2圈数??因为n是边长,除以2之后就是圈数。还需要判断n是否是奇数,如果是奇数的话要把最后遍历的值赋给它
4.定义每循环一个圈的起始位置startx = 0, starty = 0
5.需要控制每一条边遍历的长度,每次循环右边界收缩一位offset=1
6.开始转圈赋值
7.每转一圈,起始位置startx和starty要加一

在这里插入图片描述

代码

/**
 * @param {number} n
 * @return {number[][]}
 */
var generateMatrix = function(n) {
  let result = new Array(n).fill(0).map((item => {return new Array(n).fill(0)}))
  let  startX = startY = 0 // 起始位置
  let offset = 1 // 控制每一层填充元素个数
  let count = 1  // 更新填充数字
  let loop = ~~(n/2) // 旋转圈数
  let mid = ~~(n/2) // 中间位置
  while(loop--) {
    let i = startX
    let j = startY
    // 下面开始的四个for就是模拟转了一圈
    // 模拟填充上行从左到右(左闭右开)
    for(; j<n-offset; j++) {
      result[i][j]=count++
    }
    // 模拟填充右列从上到下(左闭右开)
    for(; i<n-offset;i++) {
      result[i][j]=count++
    }
    // 模拟填充下行从右到左(左闭右开)
    for(;j>startY;j--) {
      result[i][j]=count++
    }
    // 模拟填充左列从下到上(左闭右开)
    for(;i>startX;i--) {
      result[i][j]=count++
    }
    // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
    startX++
    startY++
    // offset 控制每一圈里每一条边遍历的长度
    offset++
  }
  // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
  if (n % 2) {
    result[mid][mid] = count;
  }
  return result

};

重点和收获

1.定义一个二维数组:let result = new Array(n).fill(0).map((item => {return new Array(n).fill(0)}))
2.关于offset不太好理解:offset的意义在于 结束一圈后 起始位置向后移 结束位置向前移。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值