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

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

977. 有序数组的平方

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

思路:

  • 在原始数组里,绝对值最大的数就在数组两端,所以乘方最大的数在数组两端
  • 使用双指针思想,将数组两端绝对值较大的数,塞入要输出的数组中
  • 两指针相遇循环结束
  • 塞入方式为尾插法,塞完后数组是递减的,所以要再反转一下变成递增

时间复杂度:O(2n),感觉这么说准确一点,便利原始数组复杂度是O(n),反转数组也是O(n)

空间复杂度O(n)

代码:


class Solution
{
public:
    vector<int> sortedSquares(vector<int> &nums)
    {
        std::vector<int> res;
        int length = nums.size();
        int front = 0;
        int back = length - 1;
        while (front <= back)
        {
            // 找数组两侧绝对值更大的数
            // 一定就是当前数组中乘方值最大的数
            if (abs(nums[front]) > abs(nums[back]))
            {
                res.push_back(nums[front] * nums[front]);
                ++front;
            }
            else
            {
                res.push_back(nums[back] * nums[back]);
                --back;
            }
        }
        // 当前数组是一个(非单调)递减数组,需要反转
        std::reverse(res.begin(),res.end());
        return res;
    }
};

总结:

  • 不算太难,比较容易想到,美中不足是输出数组的长度是确定的
  • 其实可以直接初始化数组,然后从后向前塞入数据
  • 这样可以节省一次反转的时间复杂度
  • 做题体验:哈哈哈哈 > 嘿嘿 > 哎哎 > 嘤嘤
  • 时间:未计
  • 一刷

209. 长度最小的子数组

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

思路:

  • 该题为了实现O(n)的时间复杂度,用了j作为连续数组头,j为连续数组尾
  • 先递增j累加数组的值,当值大于等于target的时候
  • 开始试试看把i指向的尾巴删了能不能满足,可以删一个就再删第二个试试
  • 当和比target小的时候再移动j
  • 对每种满足的情况记下j和i的差值,代表数组长度,最后输出最小值

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

代码:


class Solution
{
public:

    // 滑动窗口:

    int minSubArrayLen(int target, vector<int> &nums)
    {
        int i = 0;
        auto result = INT32_MAX;

        int sum = 0;
        for (int j = 0; j < nums.size(); j++)
        {
            sum += nums[j];
            while (sum >= target)
            {
                int sum_l = j - i + 1;
                result = std::min(result, sum_l);
                sum -= nums[i];
                ++i;
            }
        }
        if (i == 0 && sum < target)
            return 0;
        return result;
    }
};

总结:

  • 除了暴力法没想出来解法,看了cral哥的视频,算是滑动窗口初体验
  • 做题体验:嘤嘤哈哈 > 嘿嘿 > 哎哎 > 嘤嘤
  • 时间:未计
  • 一刷

59. 螺旋矩阵 II

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

思路:

  • 我这个代码的思路和carl哥有所出入,记下来以免自己以后忘了
  • 我在代码里将数组的写入分为四种阶段,并且是依序变化的
  • 向右、向下、向左、向右
  • 数组越界或者写入位置已有数值都会使方向改变
  • 输出完n*n个数之后就结束

时间复杂度:O(n),空间复杂度O(1),这个应该算原地吧,输出不能比这更小了

代码:


class Solution
{
public:
    enum zhuanquan // 一个枚举类,四个写入方向是依序变化的
    {
        right = 0,
        down,
        left,
        up
    };
    vector<vector<int>> generateMatrix(int n)
    {
        vector<vector<int>> res(n, vector<int>(n, 0));
        int direction = 0; // 和枚举配合使用,0代表向右,以此类推
        int count = 1; // 要写入的指
        int target = n * n; // 
        int i = 0; // 写入的初始行
        int j = 0; // 写入的初始列
        while (count <= target)
        {
            switch (direction)
            {
            case right: // 以向右写入为例
            {
                if (j >= n) // 判断是否越界
                {
                    direction = (direction + 1) % 4; // 改变方向
                    ++i; // 进一行(下一个方向写入的起始位置)
                    --j; // 退一列(上一轮循环多加了)
                }
                else if (res[i][j] != 0) // 判断是否已写入数据
                {
                    direction = (direction + 1) % 4;
                    ++i;
                    --j;
                }
                else
                {
                    res[i][j] = count++;
                    ++j;
                }

                break;
            }
            case down:
            {
                if (i >= n)
                {
                    direction = (direction + 1) % 4;
                    --j;
                    --i;
                }
                else if (res[i][j] != 0)
                {
                    direction = (direction + 1) % 4;
                    --j;
                    --i;
                }
                else
                {
                    res[i][j] = count++;
                    ++i;
                }
                break;
            }
            case left:
            {
                if (j < 0)
                {
                    direction = (direction + 1) % 4;
                    --i;
                    ++j;
                }
                else if (res[i][j] != 0)
                {
                    direction = (direction + 1) % 4;
                    --i;
                    ++j;
                }
                else
                {
                    res[i][j] = count++;
                    --j;
                }
                break;
            }
            case up:
            {
                if (i < 0)
                {
                    direction = (direction + 1) % 4;
                    ++j;
                    ++i;
                }
                else if (res[i][j] != 0)
                {
                    direction = (direction + 1) % 4;
                    ++j;
                    ++i;
                }
                else
                {
                    res[i][j] = count++;
                    --i;
                }
                break;
            }

            default:
                break;
            }
        }

        return res;
    }
};

总结:

  • [TODO]有空按照carl哥的思路手敲一遍
  • 做题体验:嘿嘿哈哈 > 嘿嘿 > 哎哎 > 嘤嘤
  • 时间:未计
  • 一刷

总结

个人感觉carl哥的这个题目列表中,数组的题目都以双指针为主,此外还遇到了一道滑动窗口的题目,慢慢做吧,以后对做题的理解肯能会更深刻

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值