代码随想录day2 | 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II

文章目录

    • 一、977.有序数组的平方
    • 二、209.长度最小的子数组
    • 三、59.螺旋矩阵II

一、977.有序数组的平方

977.有序数组的平方
暴力法:O(NlogN) 先所有数字平方,然后再快排,时间复杂度取决于快排

class Solution
{
public:
    vector<int> sortedSquares(vector<int> &nums)
    {
        for (int i = 0; i < nums.size(); i++)
        {
            nums[i] = nums[i] * nums[i];
        }
        sort(nums.begin(), nums.end());
        return nums;
    }
};

双指针解法:O(N)
代码随想录day2 | 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II_第1张图片


代码随想录day2 | 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II_第2张图片

class Solution
{
public:
    vector<int> sortedSquares(vector<int> &nums)
    {
        int i = 0;
        int j = nums.size() - 1;
        int k = nums.size() - 1; // 控制res的下标,初始为最大值
        vector<int> res(nums.size(), 0);
        // 为啥取等号?i==j
        for (; i <= j;)
        {
            if (nums[i] * nums[i] > nums[j] * nums[j])
            {
                res[k] = nums[i] * nums[i];
                k--;
                i++;
            }
            else // nums[i]==nums[j]?
            {
                res[k] = nums[j] * nums[j];
                k--;
                j--;
            }
        }
        return res;
    }
};

1、为啥取等号?i==j

因为当nums[i]==nums[j]的时候循环还是要继续的,还要继续处理。

2、else 中nums[i]==nums[j]?

始终都要拿那个最大的数,去到第三方数组中,所以写在if和else中都可以。

二、209.长度最小的子数组

209.长度最小的子数组
暴力法:O(N2) 两层for循环

滑动窗口(双指针):O(N)
使用一个for循环,做了两个for循环的事情。
j 代表的是终止位置的下标,如果代表的是起始位置,那么后边的数字依旧需要遍历,那么和暴力有啥区别呢。
滑动窗口的精华就是,如何移动起始位置?当我们发现sum >=tar的时候,意思就是起始位置到终止位置的长度是符合要求的,那么起始位置就后移一位。

class Solution
{
public:
    /*
    i 窗口的起始位置
    j 窗口的终止位置
    sum 窗口中值的和
    sublen 窗口的长度
    res 记录结果,每次更新,初值为INT_MAX
    */
    int minSubArrayLen(int tar, vector<int> &nums)
    {
        int sum = 0;
        int sublen = 0;
        int res = INT_MAX;
        for (int i = 0, j = 0; j < nums.size(); j++)
        {
            sum += nums[j];
            while (sum >= tar) // if 还是 while
            {
                sublen = j - i + 1;
                res = min(sublen, res);
                sum -= nums[i];
                i++;
            }
        }
        return res == INT_MAX ? 0 : res;
    }
};

1、if 还是 while?

我们来看一种特殊情况:
代码随想录day2 | 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II_第3张图片
使用if只能判断一次,但是遇到特殊情况下,这个窗口需要持续变化,那么只能用while。

2、while(sum >= tar)

到达这后,便要开始更新窗口的起始位置了。

3、return res == INT_MAX ? 0 : res; —?

有可能nums中没有符合要求的子序列,返回0即可。

三、59.螺旋矩阵II

59.螺旋矩阵II
面试中经常出现
这种模拟题最简单的还是在草稿纸上画一画!!!

模拟:O(N2)

循环不变量
坚持一个规则来处理每一条边,按照左闭右开的规则
代码随想录day2 | 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II_第4张图片

class Solution
{
public:
    vector<vector<int>> generateMatrix(int n)
    {
        vector<vector<int>> res(n, vector<int>(n, 0));
        int loop = n / 2;
        int mid = n / 2;            // 矩阵中间的位置
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int count = 1;              // 记录每个填入res中的值
        int offset = 1;             // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i, j;                   // 用于控制循环
        while (loop--)
        {
            // ①
            for (j = starty; j < n - offset; j++)
                res[startx][j] = count++; // 注意后置加加,行不变,列一直在+1
            // ②
            for (i = startx; i < n - offset; i++)
                res[i][j] = count++; // i在+1,j用的就是上面那行for循环剩下的j
            // ③
            for (; j > starty; j--)
                res[i][j] = count++;// i,j初始都是用的上面那行for循环剩下的作为初始值
            // ④
            for (; i > startx; i--)
                res[i][j] = count++;// i,j初始都是用的上面那行for循环剩下的作为初始值

            startx++;
            starty++;
            offset++;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2 == 1)
        {
            res[mid][mid] = count;
        }
        return res;
    }
};

1、while(?)

我们这个循环应该转几圈呢?当n==3时我们要循环2圈,当n ==4时,要循环2圈。注意n为奇数的处理。

2、注意坐标中(x,y)与数组[i] [j]

数学坐标往右走确实变的是x,但在数组[i][j]中:向右遍历时,i不变,是j++。

3、startx++; starty++;

第二圈开始的时候,起始位置要各自加1。

4、offset++

控制每一圈里每一条边遍历的长度。

你可能感兴趣的:(笔试强训,矩阵,算法,数据结构)