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

Day2-数组2023.9.15

Leetcode977 有序数组的平方

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

初解

我还是不能想到暴力解法之外的,对某个问题的最优复杂度也没有概念。就算提示我是用指针,我也想不到思路。
现在我知道的指针主要有快慢指针和双向指针。
受昨天那个原地换位置的影响,我也下意识没有想到新开一个数组。

看完解答

思路很简单:开一个新的数组,依次放进最大的数。最大的数必然在两侧(绝对值最大)。每次放进一个数,左右指针移动即可。
实现也很简单我一次就过了。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int len=nums.size();
        int l=0,r=len-1;
        // 最大的一定在两头。
        vector<int> res;
        res.resize(len);
        int p=len-1;
        while(p>=0&&l<=r){
            if(nums[l]*nums[l]>nums[r]*nums[r]){
                res[p--]=nums[l]*nums[l];
                l++;
            }else{
                res[p--]=nums[r]*nums[r];
                r--;
            }
        }
        return res;
    }
};

Leetcode209 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

初解

滑动窗口吧,会不了一点,暴力又是\(O(n^2)\),看答案去

看完解答

小小的误区

哦我已经完全理解了.jpg
从原来的\(O(n^2)\)暴力解法下降复杂度,只能减少一个循环。在暴力解法中,我们的第一个循环是窗口起点,第二层循环是窗口终点,判断到和>=targetbreak第二层。如果要减少一个循环,我们需要确定循环变量代表什么,循环节干什么,循环节之间怎么办。
滑动窗口的思想是,把窗口终点当循环变量。据题解说这是因为如果把窗口起点当循环变量的话,想要走到终点,还是要用一个循环的。而当我们把窗口终点当作循环变量的话,可以沿用上一个循环节的起点(+1)!要不然该循环节的长度也不是最小的,我们就不用管它了!而如果你用窗口起点当循环变量,终点是有可能缩回来也有可能右移的,这样谁能写得出来呢!多么天才啊!我去!
但是我还是有一个误解。我总觉得在一个循环节内,要找到最优解,然后比较每个局部最优解。如果我这么想的话,我会让窗口起点右移直到区间之和第一次不满足要求为止,之后再计算区间长度。这样会导致一个问题:此时区间起点指针已经多右移了一下。如果我简单地让它左移一下,还要考虑全区间加起来也不满足要求的情况,左移也不满足要求啊!还可能走到-1!

没有关系,我会上奇技淫巧

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int len=nums.size();
        int sum=0;
        int i=0;
        int res=999999;
        for(int j=0;j<len;++j){
            sum+=nums[j];
            // find i
            int flag=0;
            while(sum>= target&&i<=j){
                // move right
                sum-=nums[i++];
                flag=1;
            }
            if(flag){
                i--;sum+=nums[i];
                int tmplen=j-i+1;
                res=tmplen<res?tmplen:res;
            }
        }
        if(res==999999){
            return 0;
        }else{
            return res;
        }
    }
};

我这里让它判断,有右移才倒带,就可以通过了。但是面试官还是可能觉得我是傻逼。

找到全部解

我从题解那里抄来一个优雅的解法


class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int len=nums.size();
        int sum=0;
        int i=0;
        int res=999999;
        for(int j=0;j<len;++j){
            sum+=nums[j];
            while(sum>= target&&i<=j){
                int tmplen=j-i+1;
                res=tmplen<res?tmplen:res;
                sum-=nums[i++];
            }
        }
        if(res==999999){
            return 0;
        }else{
            return res;
        }
    }
};

它的思想略和我不同,他寻找了每一个解,在每一个解里面更新最短长度。我们可爱的计算机很擅长做重复的事情,它不会觉得麻烦!

Leetcode59 螺旋矩阵 II

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

初解

这是一个模拟过程的题目,但是我喜欢写函数,在leetcode的类里面想紫砂,而且本地的vscode不知道哪里烂完了,我哪天重新配下环境,没法调bug。累了。
修好环境了,还是不对。。首先我不会vector二维数组初始化

vector<vector<int> > matriX(n, vector<int>(n, 0)); 

看完解答

非常痛苦地写完了。
问题有二:
1.搞错旋转方向。向左写成向上。可能是累了吧。可以按计概的时候设置全局数组解决。
2.换边长的时候坐标没有切换到向右,还在向上,导致覆盖了。解决办法就是在每一次边长的末尾手动调整一下当前光标。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int> > matriX(n, vector<int>(n, 0)); 
        int cnt=1;//填入内容
        int i=0,j=0;
        for(int len=n-1;len>0;len=len-2){
            //每一段边长有四条边,分别是顺时针四个方向。
            //->
            for(int k=0;k<len;++k){
                matriX[i][j++]=cnt++;
            }
            // ↓
            for(int k=0;k<len;++k){
                matriX[i++][j]=cnt++;
            }
            // <-
            for(int k=0;k<len;++k){
                matriX[i][j--]=cnt++;
            }
            for(int k=0;k<len;++k){
                matriX[i--][j]=cnt++;
            }
            i++;j++;
        }
        if(n%2){
            matriX[n/2][n/2]=n*n;
        }
        return matriX;
    }
};
posted @ 2023-09-15 20:42  杰克40001  阅读(403)  评论(0)    收藏  举报