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

一、知识点

1、创建数组

1)vector<int> arr(nums.size(), 0);

创建了一个整数类型的vector(通常称为一维数组或向量),并将其大小初始化为nums.size(),同时将所有元素初始化为0。

2)vector<vector<int>> res(n, vector<int>(n, 0));

创建了一个 n x n 的二维整数向量(矩阵),并将所有元素初始化为0。

  • vector<int>(n, 0):这部分创建了一个大小为 n 的一维整数向量,并将所有元素初始化为0。
  • vector<vector<int>> res(...):这部分创建了一个二维整数向量 res
  • res(n, vector<int>(n, 0)):这表示 res 是一个包含 n 个元素的二维向量,其中每个元素都是一个由 vector<int>(n, 0) 创建的一维向量。

二、题目

977. 有序数组的平方

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

做题思路

数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

总体思路:使用双指针法,i 指向起始位置,j 指向终止位置。比较数组两端平方的最大值

如果 i 所在的值大,用 i 的下一位比;如果 j 所在的值大,用 j 的前一位比

代码细节

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int max, i, j;
        // 返回 每个数字的平方 组成的新数组arr
        vector<int> arr(nums.size(), 0);
        // 新数组长度 同 整数数组 nums
        int p = nums.size() - 1;
        // 数组平方的最大值就在数组的两端
        // i 指向起始位置,j 指向终止位置,比较数组两端平方的最大值
        for(i = 0, j = nums.size() - 1; i <= j;)
        {
            // 找到数组平方的最大值
            if(nums[i] * nums[i] > nums[j] * nums[j])
            {
                max = nums[i] * nums[i];
                // 如果 i 所在的值大,用 i 的下一位比
                i++;
            }
            else
            {
                max = nums[j] * nums[j];
                // 如果 j 所在的值大,用 j 的前一位比
                j--;
            }
            // 把最大值赋值给新数组
            arr[p] = max;
            p--;
        }
        return arr;
    }
};

209. 长度最小的子数组

题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/

视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE

文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html

做题思路

1)滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。

滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。

2)在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的结束位置?
  • 如何移动窗口的起始位置?

窗口就是 满足其和 ≥ target 的长度最小的 连续 子数组。

窗口的结束位置就是外层for循环的 j 。

如果当前窗口的值大于等于 target 了,窗口就要向前移动了(也就是 i 该更新了,窗口该缩小了)。

3)总体思路:先找窗口的终点,再缩小窗口,找窗口的起点(必须满足其和 ≥ target )

代码细节

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int min_len = INT32_MAX;
        int len = 0;
        int sum = 0;
        int i = 0;
        
        // j为终点,找到窗口的终点
        for(int j = 0; j < nums.size(); j++)
        {
            sum += nums[j];
            // i为起点,找到窗口的起点。找到总和大于等于 target 的长度最小的子数组
            while(sum >= target)
            {
                // 更新长度
                len = j - i + 1;
                // 找到最小长度
                if (len < min_len) min_len = len;
                // 难点:缩小窗口,更新总和
                sum -= nums[i];
                // 更新窗口的起点
                i++;
            }
        }
        // 特殊情况:如果 min_len 依旧为初值,那么说明不存在符合条件的子数组
        if(min_len == INT32_MAX) return 0;
        else return min_len;
    }
};

59. 螺旋矩阵

题目链接:https://leetcode.cn/problems/spiral-matrix-ii/

做题思路

1)如果要写出正确的二分法一定要坚持循环不变量原则。

区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。

2)总体思路:模拟转圈+赋值。坚持每条边左闭右开的原则。

代码细节

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        // 创建一个零矩阵
        vector<vector<int>> res(n, vector<int>(n, 0));
        // 定义每次循环圈的起始位置
        int start_x = 0, start_y = 0;
        // 螺旋矩阵循环几次圈。例如n为奇数3,那么loop = 1 
        int loop = n / 2;
        // n为奇数时,矩阵中间的位置。例如n为5,中间位置为(2, 2)
        int mid = n / 2;
        // 计数
        int cnt = 1;
        // 偏移量。offset 控制每一条边遍历的长度
        int offset = 1;
        // 转圈+赋值
        while (loop--)
        {
            int i = start_x;
            int j = start_y;
            // 模拟转圈,坚持每条边左闭右开的原则
            // 上行,i不变,都是第 i 行
            for (j; j < n - offset; j++)
            {
                res[i][j] = cnt;
                cnt++;
            }
            // 右列,j不变,都是第 j 列
            for (i; i < n - offset; i++)
            {
                res[i][j] = cnt;
                cnt++;
            }
            // 下行,i不变,都是第 i 行,等于start_y
            for (; j > start_y; j--)
            {
                res[i][j] = cnt;
                cnt++;
            }
            // 左列,j不变,都是第 j 列
            for (; i > start_x; i--)
            {
                res[i][j] = cnt;
                cnt++;
            }

            // 开始第二圈,起始位置更新,偏移量更新
            // 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            start_x++;
            start_y++;            
            offset++;
        }
        // 特殊情况:如果n为奇数,需要单独给矩阵最中间的位置赋值
        if(n % 2) res[mid][mid] = cnt;
        return res;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值