Day2 数组(二)


day2 2023.11.30
代码随想录

1. 977有序数组的平方
第二天做题就遇到点问题了,首先对于该题,简单的暴力平方排序肯定没问题,但一定不是我们要的最优解,我们争取在O(n)的时间复杂度内解决问题,发现对于一个初始数组,平方后的最大值,一定是在两边的。因此可以同时从两边开始索引处理,也就是昨天做的双指针思想。
但是,在开始动手后出了问题,开始想在原始数组上进行更新,但是逻辑理不清。我的想法是,对比两个指针的平方,较大得更新末尾指针,较小的存储在一个temp中,用于下一次循环判断,感觉思路是可以的,但实现起来就有问题,首先,每次循环需要跟上一次temp判断,在两者进行对比。两层if嵌套。。。屎山代码得感觉了。其次在后续更新中也有点问题,每次只能更新一个快指针值,但会有剩余值无法更新,因此该思路哪怕可行,但过于繁琐。看了一眼代码随想录正解,发现重新定义了个result数组。。。直接傻眼了,茅塞顿开。。
因此最终声明两个快慢索引,在for循环更新到result中,即可!代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> result(nums.size());
        int lowindex = 0;
        int fastindex=nums.size()-1;
        for(int i=nums.size()-1; i>=0;i--){
            if(nums[fastindex]*nums[fastindex]>=nums[lowindex]*nums[lowindex]){
                result[i] = nums[fastindex]*nums[fastindex];
                fastindex--;
            }
            else{
                result[i] = nums[lowindex]*nums[lowindex];
                lowindex++;
            }
        }
        return result;
    }
};

2. 209长度最小的子数组
这个题有些难度,首先最直观的做法就是暴力循环,两层佛如,第一层for是子数组,内层for是找到符合要求的最小数组,尝试写了写该暴力方法,测试通过,但提交后当数值过大时出现时间超出限制得问题,因此显然不是最优解:

//暴力遍历法
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int Rlength=INT32_MAX;
        int sum;
        int SLength;
        for(int i=0;i<nums.size();i++){
            sum=0;
            SLength=0;
            for(int j=i;j<nums.size();j++){
                sum+=nums[j];
                SLength++;
                if(sum>=target){
                    Rlength = SLength < Rlength ? SLength:Rlength;
                    break;
                }
            }
        }
        return Rlength==INT32_MAX? 0:Rlength;
    }
};

本题真正做法则是滑动窗口法,该方法确实不太了解,因此直接看代码随想录文字讲解,自己在尝试写代码;暴力法中两层for代表了数组起始位置和终止位置,因此滑动窗口则是一个for解决两个问题,那么是该控制起始位置还是终止位置呢,显然,如果控制起始位置,那怎么找终止位置?因为找终止位置得过程一定是需要遍历得,因此滑动窗口得for循环中心是控制终止位置,当然需要通知控制起始位置,因此也需要两个指针,也是双指针得思想。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int RLength=INT32_MAX;
        int sum=0;
        int SLength=0;
        for(int j=0, i=0;j<nums.size();j++){
            sum +=nums[j];
           // SLength++;
            while(sum>=target){
               // SLength--;
                SLength = (j-i+1);
                RLength = RLength<SLength ? RLength:SLength;
                sum -=nums[i++];
            }
        }
        return RLength==INT32_MAX ? 0:RLength;
    }
};

开始我在写代码时,使用的是注释掉的方法记录子数组的长度,并且在暴力方法时也是这样,但这里出现了问题,想着,如果总和超了,起始位置前进时,数组长度减一就好了,但有一种情况,如果现在超了,但减一后又不够,你如果提前减一,在记录长度就有问题,长度应该是减一之前的长度,记录到这里,突然灵光一闪,本来放弃了原本记录长度的方法,但是,突然发现问题所在了,尝试将两行代码位置互换,先记录长度,在减少。就通过啦!!!

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int RLength=INT32_MAX;
        int sum=0;
        int SLength=0;
        for(int j=0, i=0;j<nums.size();j++){
            sum +=nums[j];
            SLength++;
            while(sum>=target){
                RLength = RLength<SLength ? RLength:SLength;  //这里
                SLength--;  //这里
                sum -=nums[i++];
            }
        }
        return RLength==INT32_MAX ? 0:RLength;
    }
};

因此该方法,我个人认为有个混淆点就是在前进起始位置时,前进与更新长度的顺序问题,应该是先更新位置,再前进起始位置。while中带等号。
总体表达意思:在终止位置固定时,哎呦,现在子数组之和满足要求了唉,那我先记录下来目前的长度,再尝试将起始位置前进一下,咦,依然满足啊,那就再前进一下。。。哦,不满足啦,那最小的就是我上一个记录的啦!再比较与不同终止位置时的最小长度,更新最终最小长度!!!ok!结束!

3. 59螺旋矩阵
螺旋矩阵,很久之前写过,但又忘了,借此机会复习一下,自己写的时候以为两层for循环,更新行列值,想了很久该怎么组织逻辑关系,理不清,最后看代码随想录文字讲解,是按照每一圈为一个循环,每次循环分为四部–上右下左的顺序赋值,达到目的,不过变量有点多,开始没有写遍历长度这个变量,测试通过,但当n=4时就报错了,最后理一遍所有变量;
首先,每层循环的起始点不一样,因此需要两个变量为每次循环提供起始点,并在循环结束后加1.
其次,二维数组的索引肯定需要两个变量
之后,对于n的奇偶不同,结果不同,如果是偶数,则循环为整数,不会落单。但如果为奇数,比如3,想一想,一圈处理后只剩中间一个,因此需要特殊处理,所以需要一个变量代表中间索引
然后,肯定需要一个变量控制循环次数,也就是要处理几圈。
最后,也是我最开始忽略的,每一次循环的每一步处理,到哪里结束?开始以为就是n-1,但这是最外圈的,如果n大一些,比如4,在第二圈循环中,每一步少两个位置,因此减2.所以需要一个控制遍历处理长度的遍历。
最终结果如下:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> result(n, vector<int>(n));
        int startx=0,starty=0;  //位置
        int loop = n/2;  //循环几次
        int count=1;  //赋值
        int mid = n/2;  //单独处理中间
        int i,j;
        int length = 1;
        while(loop--){
            i = startx;
            j = starty;
            for(j=starty;j<n-length;j++){  //上行,左闭右开
                result[i][j] = count++;
            }
            for(i=startx;i<n-length;i++){  //右列 ,上闭下开
                result[i][j] = count++;
            }
            for(;j>starty;j--){  //下行,右闭左开
                result[i][j] = count++;
            }
            for(;i>startx;i--){  //左列,下闭上开
                result[i][j] = count++;
            }
            startx++;
            starty++;
            length++;
        }
        if(n%2){
            result[mid][mid] = n*n;  //奇数时单独处理
        }
        return result;
    }
};

你可能感兴趣的:(LeetCode刷题记录,算法,leetcode,数据结构)