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

参考文章与视频

题目一:977.有序数组的平方

题目描述

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。977. 有序数组的平方 - 力扣(LeetCode)

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

要求:时间复杂度为 O(n)

第一想法

遍历数组计算每一项元素的平方,然后排序。排序时间复杂度要求O(n),这里没什么想法,想到的时间复杂度都超过了O(n)。

看完代码随想录之后的想法

需要注意的是,原数组其实也是有序的,但是因为负数平方后可能会大于所以造成了平方后的无序。但这种情况下负数部分平方后也是有序的,由大到小。这时,我们可以设定左右指针,分别从前向后,从后向前移动比较,并从后向前填入新数组中。

var sortedSquares = function(nums) {
    let len = nums.length;
    let arr = new Array(len).fill(0);
    let left = 0;
    let right = len - 1;
    for(let i = len-1; i >=0 ; i--) {
        if(nums[left]*nums[left] > nums[right]*nums[right] ) {
            arr[i] = nums[left]*nums[left];
            left++;
        } else {
            arr[i] = nums[right]*nums[right];
            right--;
        }
    }
    return arr;
};

题目二:209.长度最小的子数组

题目描述

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

输入:s = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

第一想法

遍历数组 ,以当前数组元素为起始子数组找到满足和大与等于s的数组,并记录,如果找到长度更小的就更新记录直到最后。

var minSubArrayLen = function(target, nums) {
            let result = nums.length;
            let flag = false;
            let len = 0;
            for (let i = 0; i < nums.length; i++) {
                let sum =0;
                for (let j = i; j < nums.length; j++) {
                    sum = sum + nums[j];
                    if (sum >= target) {
                        len = j-i+1;
                        if(len < result){
                            result = len;
                        }
                        flag = true;
                    }
                }
            }
            if (flag) {
                return result;
            } else {
                return 0;
            }
        
};

看完代码随想录之后的想法

利用双指针构建滑动窗口,不断调整指针以满足窗口所选中的子数组符合我们的目标结果。

 构建滑动窗口需要明确:

窗口包含的元素之和应大与等于target;

当窗口包含子数组满足条件,窗口起始指针应向后移动;

窗口终止指针应持续滑动直至遍历完原数组。

var minSubArrayLen = function(target, nums) {
    let result = nums.length+1;
    let sum = 0;
    let l = 0;
    for (let r = 0; r < nums.length; r++) {
        sum = sum + nums[r];
        while(sum >=target) {
            result = result > r-l+1 ? r-l+1 : result;
            sum = sum - nums[l];
            l++;
        }
    }
    if(result == nums.length+1) return 0;
    return result;
};

实现中遇到的困难

1.计算sum和符合条件的长度位置和方式很重要,长度可以直接通过j-i+1求。应先计算sum后判断是否满足target,满足则输出长度。

2.计算长度使用累加方法,增加了复杂度,每次都要重新赋值长度初值,但是这个初值很容易在最后被误当成最小值赋值给result。

3.在使用滑动窗口时,起始指针向右移动的同时也应让sum减去移出窗口的元素。

题目三:59.螺旋矩阵II 

题目描述

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

示例:

输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

第一想法

先创建一个n*n大小的数组,依次赋值。

看完代码随想录之后的想法

同样要遵循循环不变量原则,循环不变量是指控制边每次的计算区间一致,为了控制这个边每次具有相同的计算区间,我们每次填充数字应不包含该边最后一个点,应把最后一个节点交给下一条边处理。

 

var generateMatrix = function(n) {
    let startX = startY = 0;   // 起始位置
    let loop = Math.floor(n/2);   // 旋转圈数
    let mid = Math.floor(n/2);    // 中间位置
    let offset = 1;    // 控制每一层填充元素个数
    let count = 1;     // 更新填充数字
    let res = new Array(n).fill(0).map(() => new Array(n).fill(0));

    while (loop--) {
        let row = startX, col = startY;
        // 上行从左到右(左闭右开)
        for (; col < startY + n - offset; col++) {
            res[row][col] = count++;
        }
        // 右列从上到下(左闭右开)
        for (; row < startX + n - offset; row++) {
            res[row][col] = count++;
        }
        // 下行从右到左(左闭右开)
        for (; col > startY; col--) {
            res[row][col] = count++;
        }
        // 左列做下到上(左闭右开)
        for (; row > startX; row--) {
            res[row][col] = count++;
        }
        // 更新起始位置
        startX++;
        startY++;
        // 更新offset
        offset += 2;
    }
    // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
    if (n % 2 === 1) {
        res[mid][mid] = count;
    }
    return res;
};

实现中遇到的困难

如果n为奇数的话,需要单独给矩阵最中间的位置赋值

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值