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

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

学习文档链接: 代码随想录

一、977.有序数组的平方

链接: 有序数组的平方

该题两种思路:

(1)暴力排序:每个数平方之后,排个序,时间复杂度是 O(n + nlogn)。
(2)双指针:数组其实是有序的,只是负数可能会导致平方很大,考虑使用双指针实现,左指针指向起始位置,右指针指向末尾。定义一个新数组result,其大小与原数组相同,让k指向数组的末尾,判断左右指针指向位置数的平方大小,将较大的先插入新数组即可。双指针的时间复杂度为O(n),相对于暴力排序的解法O(n + nlog n)还是提升不少的。

(1)暴力排序代码:

//新建数组然后使用push_back()插入。
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> result;
        for(int a : nums){
            result.push_back(a*a);
        }
        sort(result.begin(),result.end());
    return result;
    }
    
};
//直接更改原数组,使用for(int a : nums)遍历时,若要更改数组元素,加引用才行,若不加引用,改不了原数组。
//使用for(int i = 0;i<nums.size();i++)遍历,结果与该方法一致。
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        for(int &a : nums){
            a*=a;
        }
        sort(nums.begin(),nums.end());
        return nums;
    }
    
};

(2)双指针代码:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> result(nums.size(), 0); //初始化之后就可以使用数组形式添加数据
        //vector<int> result;  如果不初始化,那么后续只能使用push_back()添加数据,使用下面方式会直接报如下错误。
        int left = 0;
        int right = nums.size() - 1;
        int k = nums.size()-1;
        while(left<=right){
            if(nums[left]*nums[left]<=nums[right]*nums[right]){
                result[k--] =nums[right]*nums[right];
                right--;
            }
            else
            {
                result[k--] =nums[left]*nums[left];
                left++;
            }
            
        }
        return result;
    }
};

不初始化数组的报错信息:
不初始化数组的报错信息


二、209.长度最小的子数组

链接: 长度最小的子数组
两种思路:

(1)暴力遍历,一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。时间复杂度为O(n^2),由于题目中1 <= nums.length <= 10^5,所有在力扣里面会超时。
(2)滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果,本质也就是双指针。那么滑动窗口如何用一个for循环来完成这个操作呢。
首先要思考如果用一个for循环,那么应该表示滑动窗口的起始位置,还是终止位置。如果只用一个for循环来表示 滑动窗口的起始位置,那么如何遍历剩下的终止位置?此时难免再次陷入暴力解法的怪圈。所以 只用一个for循环,那么这个循环的索引,一定是表示滑动窗口的终止位置。

(1)暴力遍历法
时间复杂度为o(n^2),详细代码如下:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

(2)滑动窗口

可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int left = 0;
        int subLength = 0;
        int result = INT32_MAX;
        int sum=0;
        for(int right = 0;right<nums.size();right++){
            sum += nums[right];
            while(sum>=target){
                subLength = right-left+1;
                result = min(result,subLength); //要在while里面执行min()。
                sum -= nums[left];
                left++;
            }
        }
        if(result ==INT32_MAX)
            return 0;
        else
            return result;
    }
};

三、59.螺旋矩阵II

链接: 螺旋矩阵II
思路:

这道题目可以说在面试中出现频率较高的题目,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。
求解本题依然是要坚持循环不变量原则。
模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
由外向内一圈一圈这么画下去。

关键点:这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
在这里插入图片描述

详细代码如下:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int> > Matrix(n,vector<int>(n,0));
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int num = 1;
        int i,j;
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int loop =n/2;
        int mid =n/2;
        while(loop--){
            i = startx; 
            j = starty;
            //左闭右开
            for (; j < n - offset; j++) {
                Matrix[i][j] = num++;
            }
            for (i; i < n - offset; i++) {
                Matrix[i][j] = num++;
            }
            for (; j > starty; j--) {
                Matrix[i][j] = num++;
            }
            for (; i > startx; i--) {
                Matrix[i][j] = num++;
            }

            startx++;
            starty++;

            offset += 1;
        }
        if (n % 2) {
            Matrix[mid][mid] = num;
        }
        return Matrix;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值