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

有序数组的平方:

题目链接:力扣

知识点:双指针。

思路分析:首先想到的是不怎么动脑子的暴力想法,即先将vector中的各元素用pow函数进行平方,接着再用sort函数对已平方过的数据进行排序。
但是由于sort是基于快速排序法的,故做的的时间复杂度是O(nlogn),且这种个方法不能很好的利用“有序数组”这一特点
有没有复杂度更低一些的方法呢? 这里采用了双指针的方式,left指向vector的头,right指向vector的尾部,比较left和right所指向数据的平方,接着谁大就将谁的平方放入新开辟vector(大小同原有vector)的尾部,并将left或right指针向中间移动。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
       vector<int> Result(nums.size(),0);
       int Index = nums.size()-1;
       int left = 0;
       int right = nums.size()-1;

       while(left <= right)
       {
           if(pow(nums[left],2)>pow(nums[right],2))
           {
               Result[Index] = pow(nums[left],2);
               left++;
           } 
           else
           {
               Result[Index] = pow(nums[right],2);
               right--;
           }
           Index--;
       }
       return Result;
    }
};

此时时间复杂度为O(n)。

长度最小的子数组:

题目链接:力扣

知识点:滑动串口,双指针,即就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

思路分析:这题拿到时候,想法和题解差不多,总得来说就是left指针和right指针在最开始时同时指向vector的头,随后right节点不断向右移动,当区间[left,right]之间的值和为target时,记录下此时的子数组长度,下一步将left向右移一步,再将right不断向右移……,同时之后的每次寻找到的子数组长度都与之前的最小子数组长度做比较。

出现的问题:其实思路上还是比较清晰的,但是写的时候会有各种小问题,特别是在边界的定义上。

以下贴上我初次答题是的代码:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {

        int left = 0;
        int right = 0;
        int sum = nums[left];
        int minsize = INT_MAX;

        while(left <= right && right <= nums.size()-1)
        {
            if(sum < target)
            {
                right++;
                if (right<= nums.size()-1)  sum += nums[right];
                
            }
            else if(sum >= target)
            {
                minsize = minsize < (right - left + 1) ? minsize: (right - left + 1);
                cout<< sum<<" "<<left<<" "<<right<<" "<<minsize << endl;

                sum -= nums[left];
                left++;
            }
        }

        return (minsize==INT_MAX) ? 0: minsize);

    }
};

虽然思路是一样的,但相比而言,卡哥给出的答案更加简洁

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; // 滑动窗口数值之和
        int i = 0; // 滑动窗口起始位置
        int subLength = 0; // 滑动窗口的长度
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

时间复杂度O(n),空间复杂度O(1)。

螺旋矩阵II

题目链接:力扣

注意点:此题属于模拟过程题,做这题时,有想到卡哥第一天讲到的循环不变法则,画四个边的边界条件都要控制的是一条原则,这样思考写出来的代码才不会混乱
如面对一个3*3的矩阵,
上边界只填充[0,0], [0,1]
右边界只填充[0,2], [1,2]
下边界只填充[2,2], [2,1]
左边界只填充[2,0], [1,0]
可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。坚持【左闭右开】原则,如此依赖外围就会被全部填充完毕,并以此循环

此外还要寻找定义边界的规律,可以发现,一个边长为n的正方形,从里往外第count层(最外圈,count为0),上边界的左右两个边界为 [j,n-1-count), 右边界的上下两个边界为  [i,n-1-count),
下边界的左右两个边界为((n - 1) - (n - 1 - count), j],左边界的上下两个边界为((n - 1) - (n - 1 - count), i],其中i和j分别指行和列的索引,其会随循的改变而变化。


下面贴一下我的代码(这里和卡尔给出的答案相似):

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {

         vector<vector<int>> Res(n, vector<int>(n, 0));
        int i = 0;
        int j = 0;
        int count = 0;
        int index = 0;

        while (index != pow(n,2))
        {
            if (i == n - 1 - count && j == n - 1 - count)
                Res[i][j] = ++index;
            for (j; j < n - 1 - count; j++)
                Res[i][j] = ++index;
            for (i; i < n - 1 - count; i++)
                Res[i][j] = ++index;
            for (j; j > (n - 1) - (n - 1 - count); j--)
                Res[i][j] = ++index;
            for (i; i > (n - 1) - (n - 1 - count); i--)
                Res[i][j] = ++index;

            i++;
            j++;
            count++;
        }
        return Res;           
    }
};

后面的i++ 和 j++ 是由于前面进行了j-- 和 i--;
while中if条件的判断是为了当n为奇数时中心项的填充。

时间复杂度O(n^2),空间复杂度O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值