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

977.有序数组的平方

题目建议: 本题关键在于理解双指针思想

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

视频讲解: 双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili

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

示例 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]

最朴实无华的做法,就是将数组内的所有元素先进行平方,然后使用sort函数将数组元素排序,但时间复杂度较大,下面使用双指针的思想来解决这道题

首先我们可以根据示例来看,不管有无负数,只要是非递减顺序,最大的平方肯定在两侧,所以我们每次只需要比较最两侧的元素的平方大小,将更大的元素平方放入另一个数组存起来;

因此,我们还需要新建一个数组res,size = nums.size()。由于最后返回的数组也要按照非递减顺序,所以我们只要将更大的元素平方放在数组res的末尾,这里使用l来记录数组res的索引,l初始化为nums.size() - 1,每存入一次,l--

如果是首位元素的平方大于末位元素的平方,即将首位元素的索引left向右移位,反过来将末位元素的索引right左移,并进行下一次比较,直到left>right, 跳出循环

具体代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int left = 0;//left指向起始位置
        int right = nums.size() - 1;//right指向终止位置
        int l = nums.size() - 1;
        vector<int> res(nums.size(), 0);
        while(left <= right){
            if (nums[left] * nums[left]>= nums[right] * nums[right]){
                res[l] = nums[left] * nums[left];
                left ++;
            }else{
                res[l] = nums[right] * nums[right];
                right --;
            }
            l --;
        }
        return res;
    }
};

209. 长度最小的子数组

题目链接:. - 力扣(LeetCode)

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

找出该数组中满足其总和大于等于 target 的长度最小的 

子数组

  [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度 如果不存在符合条件的子数组,返回  0 。

示例 1:

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

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

本题需要找到长度最小的子数组,且子数组内元素总和必须大于给定的target,设定长度为l,每次找到满足条件的子数组后,都要和之前符合条件的数组长度进行比较,取最小值。

首先,要怎么知晓子数组的长度,这里的长度与元素个数有关,因此我们可以通过首尾元素的索引相减得到子数组长度;

其次,要怎么更新子数组长度,或者说使用什么样的方法来寻找下一个符合条件的子数组。假设我们从i=0开始遍历,count+=nums[i],直到count>=target找到符合条件的子数组,记录下长度l,此时有两种选择

一种是重新从i=1开始遍历,直到找到下一个符合条件的数组,也就是暴力循环的方法

另一种是利用之前相加的结果,由于原数组为正数数组,当刚好找到符合条件的子数组时,将最前面的元素减去,同时索引右移,i++,加上i=j后的元素,进行下一轮的条件循环判断,这样就能减少计算量

最后要考虑到一种计算情况,所有元素之和都不满足条件,返回0

具体代码

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int i = 0, j = 0;
        int count = 0, l = INT_MAX;
        for (i = 0;i < nums.size(); i++){
            count += nums[i]; 
            while(count >= target){
                l = min(i - j + 1, l);
                count -= nums[j];
                j++;
            }
        }
        if (l == INT_MAX) return 0;
        return l;
    }
};

这里用到了滑动窗口的思想,可以理解为两个指针的移动,其中一个是不变的,另一个是变化的,当达到某个条件的时候,将不变的指针进行移动,这样窗口的长度是能够更新变化的。

59.螺旋矩阵II

题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili

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

示例 1:

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

示例 2:

输入:n = 1
输出:[[1]]

刚开始看这题, 有点懵,外围循环能写,但是到底要循环多少次,什么时候停止

首先,在进行循环赋值的时候,需要考虑到左右的值,可以左开右闭,也可以左闭右开,但不能搞混了,否则就会重复赋值

显然,矩阵维度是n*n,同时我们需要定义每一次循环赋值的起点,这里定义起始坐标startx=0,starty=0,然后每一层赋值后,将startx++,starty++

通过观察矩阵,可以发现n=3,只需要赋值一层,n=4时,赋值两层,n=5时,赋值两层,所以循环次数(赋值)loop=n/2,而每一条边赋值结束的条件也不同,这里定义一个变量offset = 1,来更新每条边的终止条件

最后,如果n为奇数时,需要对中心的位置单独赋值

具体代码如下:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0));
        int startx = 0, starty = 0;
        int i = 0, j = 0;
        int loop = n / 2;
        int count = 1;
        int offset = 1;
        while (loop --){
            i = startx;
            j = starty;
            for (; j < n - offset; j++){
                res[i][j] = count++;
            }
            for (; i < n - offset; i++){
                res[i][j] = count++;
            }
            for (;j > starty; j--){
                res[i][j] = count++;
            }
            for (;i > startx;i--){
                res[i][j] = count++;
            }
            startx ++;
            starty ++;

            offset ++;
        }
        if (n % 2){
            res[n/2][n/2] = count;
        }
        return res;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值