代码随想录算法训练营第二天| LC977. 有序数组的平方、LC209. 长度最小的子数组、59. 螺旋矩阵II、数组章节总结

LeetCode 977 有序数组的平方

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

做题情况:一看到这道题目,很容易想到先把数组各元素平方然后排序即可,自己ac代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int n=nums.size();
        for(int i=0;i<n;i++){
            nums[i]=nums[i]*nums[i];
        }
        sort(nums.begin(),nums.end());
        return nums;
    }
};

但是这道题目进阶是设计一个时间复杂度为O(n)的算法,而上述这种容易想到且比较暴力求解的方法时间复杂度为O(nlogn),关键在sort函数快排那里,这道题目给出了一个有序非递减数组这个条件根本就没有用到,则就要在这个地方找突破口,自己当时也想到这里了,且由于在双指针部分中,所以自然也想到了双指针且指向数组前面和后面位置进行遍历,可是在写代码的时候自己选择了两个指针所指数的平方的较小值放新建数组相应位置(采用vector中的push_back方法),然后就模拟发现错误,也没反应过来找较大值然后放入数组的末尾位置即可看了卡哥视频和代码随想录书相关章节后,自己实现且ac代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int n=nums.size();
        vector<int>ret(n, 0);
        int k=n-1;
        int l=0,r=n-1;
        while(l<=r){
            int leftvalue=nums[l]*nums[l];
            int rightvalue=nums[r]*nums[r];
            if(leftvalue<=rightvalue){
                ret[k--]=rightvalue;
                r--;
            }else{
                ret[k--]=leftvalue;
                l++;
            }
        }
        return ret;
    }
};

上述实现方法是时间复杂度为O(n)

LeetCode 209 长度最小的子数组

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

做题情况:开始很容易想到暴力求解方法,但是Leetcode提交显示超出时间限制,自己暴力解法代码如下:

//暴力解法
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int ret=INT_MAX;
        int n=nums.size();
        for(int i=0;i<n;i++){
            long sum=0;//根据所给数据范围,这个地方也没必要说要定义成long数据类型
            for(int j=i;j<n;j++){
                sum +=nums[j];
                if(sum>=target){
                    ret=min(ret,j-i+1);
                }
            }
        }
        return ret==INT_MAX?0:ret;
    }
};

双指针滑动窗口的做法自己想了好久都没想出来要怎么做,然后看卡哥视频和代码随想录书相关内容,自己总结相关思路如下:每次以一个位置为终止位置进行遍历查找长度最小的子数组(相当于代码中的j,包括数组中所有的位置都可以作为终止位置),然后维护一个起始位置(相当于代码中i),从而起始位置和终止位置形成一个滑动窗口,用一个变量sum来记录窗口内的值的总和,在每一次终止位置迭代期间,比较sum和target的大小,如果sum大,就可以记录此长度然后和已有的比较进行找最小值,然后起始位置i加1,看是否有更短的长度,没有了就进行下一轮终止位置迭代,这样就省去了新一轮迭代起始位置前的所有长度的计算,因为它们肯定比前面的所记录的最小长度更长,相当于从前一个迭代的最少长度进行新一轮迭代的查找,从而达到优化,具体实现代码如下:

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

时间复杂度为O(n),不要被for循环中的while给迷惑了
感觉这种滑动窗口做法很巧妙,很难想到和实现,看了相关题目扩展后自己还是不能用这种思想去解决一些问题,相关题目这周末有时间好好去琢磨下,让自己拥有这种思维。

LeetCode 59 螺旋矩阵II

题目链接:59. 螺旋矩阵II

这道题碰到了好多次,每次碰到都没有思路和看了思路写代码实现花费大量时间,这次看了卡哥视频和代码随想录书相关部分后,觉得只要抓住不变量(此处实现采取的是左闭右开)循环圈数为奇数或偶数则会有相应思路,代码实现这个保持思路清晰边写代码边结合实例就可以写出来了,具体实现ac代码如下:

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

感觉这道题目没有什么重要思想,关键在于代码实现能力的考查

数组章节总结

简单总结一下思想:
思想:二分查找(特别注意二分查找的相关题目扩展LC 34 在排序数组中查找元素的第一个和最后一个位置和LC 35 搜索插入位置,对进一步理解二分查找很有帮助)、双指针、滑动窗口(实际上也是双指针)这种思想一定要时刻记在心中、螺旋矩阵进行模拟

今天按照步骤做下来包括写博客一共花四个小时左右,关键自己在做题和看完思路实现所花费时间较多

贵在坚持,加油,共勉

你可能感兴趣的:(代码随想录算法训练营,算法,leetcode,数据结构)