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

977.有序数组的平方 

题目

力扣题目链接

思路(双指针法)

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

如果A[i] * A[i] < A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。

如果A[i] * A[i] >= A[j] * A[j] 那么result[k--] = A[i] * A[i]; 。

动画如下:

 代码如下(JavaScript)

const nums = [-4,-1,0,3,10]
    var sortedSquares = function(nums) {
        const n=nums.length
        const res=new Array(n)  //利用构造函数创建一个新的数组
        let k=n-1      //题目要求结果从小到大排序,而下标k所表示的值是通过 比较下标i表示的值和下标j表示的值之间的较大值 赋值而来的,所以k所表示的值得从新数组的最后面倒过来开始表示
        for(i=0,j=n-1;i<=j;){  //此处for循环括号内不能盲目地直接i++和j++,i++或者j++得通过后面比较nums[i]*nums[i]与nums[j]*nums[j]两者之间谁大,来决定i++还是j++
            let left=nums[i]*nums[i]
            let right=nums[j]*nums[j]
            if(left>right){ //此处比较的是nums[i]*nums[i]与nums[j]*nums[j],而不是nums[i]与nums[j],因为数组里面包含着一些负数但绝对值大的值
                res[k--]=left   //将比较大的值赋值给res[k],然后k依次-1,往前移动一位
                i++
            }else{
                res[k--]=right  //同理
                j--
            }
        }
        return res
    };
    const result=sortedSquares(nums)
    console.log(result)

209.长度最小的子数组

题目

力扣题目链接

思路(滑动窗口)

滑动窗口: 就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,来看一下查找的过程:

最后找到 4,3 是最短距离。

其实从动画中可以发现滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。

 代码如下(JavaScript)

const nums = [2,3,1,2,4,3]  
const target = 7
var minSubArrayLen = function (target, nums) {
     let i = 0       //滑动窗口的起始位置
     let sum = 0     
     let subLen = 0
     let res = Infinity   //结果初始化为最大值
     for (j = 0; j < nums.length; j++) {
          sum += nums[j]   //随着j(滑动窗口的终止位置)的移动,逐步将nums[j]的值累加放到sum中
          //注意:这里不能使用if,因为当找到满足条件后要窗口要继续往前移动寻找新的子数组
             while (sum >= target) {
                subLen = j - i + 1  //在满足条件后,计算子数组的长度
                res = Math.min(res, subLen)   //在依次算出不同子数组的长度后,取最小值
                //在满足条件后,窗口将进行下一次的寻找,这时起始位置的指针也要向前移动一位,在此之前要先将减去一个nums[i]值
                sum -= nums[i]    
                i++
            }
      }
      /* 如果res等于最大值,则证明前面没有找到满足sum>=target条件的子数组,结果返回0;
         反之,有找到满足条件的,返回最小子数组的长度
      */
      return res === Infinity ? 0 : res
 }
 const result =minSubArrayLen(target,nums)
 console.log(result)

59.螺旋矩阵II

题目

力扣题目链接

思路

求解本题要坚持循环不变量原则。

模拟一下顺时针画矩阵的过程:

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

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

可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,一定要按照固定规则来遍历。

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

如果按照左闭右开的原则,来画一圈,大家看一下:

 代码如下(JavaScript)

var generateMatrix = function (n) {
           /* 开辟一个二维数组:先定义一个具有n个元素并初始化为0的一维数组(new Array(n).fill(0)),
              然后利用map方法,创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数(new Array(n).fill(0))后的返回值组成,相当于在原数组的每一个元素的位置再生成一个具有n个元素的一维数组,所以结果就生成一个二维数组 */
            let nums = new Array(n).fill(0).map(() => new Array(n).fill(0))
            let startx = 0  // 定义每循环一个圈的起始位置
            let starty = 0  //同理
            let loop = Math.floor(n / 2) // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
            let offset = 1 // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
            let count = 1  // 用来给矩阵中每一个空格赋值
            let mid = Math.floor(n / 2)   // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
            while (loop--) {
                // 下面开始的四个for就是模拟转了一圈
                // 模拟填充上行从左到右(左闭右开)
                for (j = starty; j < n - offset; j++) {
                    nums[startx][j] = count++
                }
                // 模拟填充右列从上到下(左闭右开)
                for (i = startx; i < n - offset; i++) {
                    nums[i][j] = count++
                }
                // 模拟填充下行从右到左(左闭右开)
                for (; j > starty; j--) {
                    nums[i][j] = count++
                }
                // 模拟填充左列从下到上(左闭右开)
                for (; i > startx; i--) {
                    nums[i][j] = count++
                }
                // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
                startx++
                starty++
                // offset 控制每一圈里每一条边遍历的长度
                offset++
            }
            // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
            if (n % 2) {
                nums[mid][mid] = count
            }
            return nums

        };

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值