代码随想录算法训练营29期Day2|LeetCode 977,209,59

 文档讲解:代码随想录

977.有序数组的平方 

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

思路:

        题目给出的数组保证有序,也就是说在数轴上是一个个点。同时我们知道,在数轴上越靠近0的点绝对值越小,其平方值也就越小。

        我们首先遍历一遍该有序数组,很容易就能找到绝对值最小的那个点。从这个点为起点,不论向左还是向右,其平方值都是非递减顺序的一个数组。此时我们的题目变为两个非递减数组的合并问题。

        两个有序数组的合并很好解决,双指针读取两个数组的值进行比较,存到第三个数组中即可。

核心代码:

class Solution {
private:
    int abs(int x){
        return x>0?x:-x;
    }
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int pos=0;
        int len=nums.size();
        vector<int> ans(len);
        for(int i=0;iif(abs(nums[i])<abs(nums[pos])) pos=i;
        }
        int l,r;
        if(nums[pos]<=0) l=pos,r=pos+1;
        else l=pos-1,r=pos;
        int cnt=0;
        while(l>=0){
            if(r==len||(nums[l]*nums[l])<=(nums[r]*nums[r])){
                ans[cnt++]=nums[l]*nums[l];
                l--;
            }
            else{
                if(rwhile(rreturn ans;
    }
};

209.长度最小的子数组

题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/

思路:

        本题要求找出长度最短的连续子数组,使其和大于等于目标值。

        我们一样可以采取双指针解决这个问题,取双指针left和right,分别表示连续子数组的左端点和右端点,其初始值均为0。

        针对当前子数组,我们统计其和sum。如果sum小于目标值target,说明还需要接着向里面读入,则right需要加1。如果sum大于等于目标值target,证明当前达到要求,可以进行滑动。

        重复以上操作,我们相当于枚举每个点为子数组左端点,同时迅速的找出了符合要求的右端点。统计所有符合要求的数组长度,取最小值即可。

        本题目是经典的滑动窗口问题。在统计sum的时候,我们可以在指针移动时对sum进行加减,也可以利用前缀和。

核心代码:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int l,r,ansl,ansr,sum;
        int len=nums.size();
        l=0;r=0;sum=0;
        ansl=0;ansr=100005;
        while(rwhile(l<=r&&sum>=target){
                if(ansr-ansl>r-l){
                    ansl=l;
                    ansr=r;
                }
                sum-=nums[l];
                l++;
            }
            sum+=nums[r];
            r++;
        }
        while(l=target){
            if(ansr-ansl>r-l){
                ansl=l;
                ansr=r;
            }
            sum-=nums[l];
            l++;
        }
        if(ansr-ansl>len) return 0;
        else return (ansr-ansl);
    }
};

59.螺旋矩阵II

题目链接:https://leetcode.cn/problems/spiral-matrix-ii/

思路:

        本题目要求将元素按顺序螺旋式填到矩阵中。

        首先手推一下过程可以知道以下信息:螺旋式的方向是有规律的,按照“右下左上”重复进行,在碰到边界之前方向都不会变。这个所谓的“右下左上”其实就是“横向右移、竖向下移、横向左移、竖向上移”。针对这四个每个过程,我们都很容易进行实现,无非就是给x坐标或者y坐标加1或减1。

        那么我们如何知道在什么时候碰到临界,或者说什么时候切换方向呢?

        首先很明显的一点是,这个n*n的矩阵,所有横纵坐标必须位于[0,n-1]之间,不能超过这个边界。其次,我们很容易知道整个填充过程其实是由外到内的,所以我们填充到当前格子时,如果下一个格子已经被填充,那我们就知道也碰到临界了,需要切换方向,下一个方向按照“右下左上”来即可。问题就此得到解决。

        另外,针对方向的处理我们其实是有小技巧的。我们可以提前写好位置向量数组dx和dy。其中dx[]={0,1,0,-1},dy[]={1,0,-1,0}。假设当前坐标为(x,y),易知(x+dx[0],y+dy[0])表示横向的下一个点,其他三个与此同理。同时我们用cnt记录方向,则0为右,1为下,2为左,3为上。需要切换方向时给cnt加1再对4取模即可。

核心代码:

class Solution {
public:
    vector> generateMatrix(int n) {
        std::vector row(n, -1);
        std::vector> ans(n, row);
        int dx[]={0,1,0,-1};
        int dy[]={1,0,-1,0};
        int x=0,y=0,cnt=0;
        for(int i=1;i<=n*n;i++){
            ans[x][y]=i;
            if(x+dx[cnt]<0||x+dx[cnt]>=n||y+dy[cnt]<0||y+dy[cnt]>=n
            ||ans[x+dx[cnt]][y+dy[cnt]]!=-1){
                cnt++;
                cnt%=4;
            }
            x=x+dx[cnt];
            y=y+dy[cnt];
        }
        return ans;
    }
};

今日总结

        今日学习时长4h,做题手感变好了很多,思路也清晰了不少。

        同时学习了一些C++的八股文。

你可能感兴趣的:(算法,leetcode,c++)