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

本文介绍了三种优化算法:暴力解法和双指针法求有序数组平方的排序,滑动窗口方法解决长度最小子数组问题,以及使用循环不变量原则生成螺旋矩阵。这些方法分别降低了时间复杂度,从O(n^2)提升到了O(n)。
摘要由CSDN通过智能技术生成

977. 有序数组的平方

// 暴力解法
// O(n + 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());  // sort采用快排
        return nums;
    }
};

```cpp
// 双指针法
// O(n)
// 思路: 先定义一个result数组,k指向其最后一个元素的位置,再定义i和j分别指向nums数组的第一个元素位置和nums数组的最后一个元素位置,比较nums[i]*nums[i]和nums[j]*nums[j]的大小,特别注意i<=j的终止条件,当i=j时也需要放入result中。
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int k = nums.size() - 1;  // k指向数组的最后一个元素
        vector<int> result(nums.size(), 0);  // 定义一个数组
        for(int i = 0, j = nums.size() - 1; i <= j;) {  // 注意终止条件i<=j,假如ij最后都指向同一个元素也需要比较后放入result中
            if (nums[i] * nums[i] > nums[j] * nums[j]) {
                result[k] = nums[i] * nums[i];
                k--;
                i++; 
            } else {
                result[k] = nums[j] * nums[j];
                k--;
                j--;
            }
        }
        return result;
    }
};

209. 长度最小的子数组

// 暴力解法
// O(n^2)
// 思路: 两层for循环,找到sum>=target的子序列长度
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT32_MAX;
        int subLength = 0;  // 子序列长度
        int sum = 0;  // 子序列和
        for (int i = 0; i < nums.size(); i++) {
            sum = 0;
            for (int j = i; j < nums.size(); j++) {
                sum += nums[j];
                while (sum >= target) {  // 这里的while需要注意,if也可以过,但需要考虑 1,1,1,1,1,100找到大于目标100,当i指向第一个1,j指向100,此时sum=105,但i++到第二个,第三个,第四个都大于100,所以采用while,用if就不是最小子序列长度了
                    subLength = j - i + 1;
                    result = result < subLength ? result :subLength;
                    break;  // 找到最小的子序列时就跳出循环break掉
                }
            }
        }
        return result == INT32_MAX ? 0: result;

    }
};

// 滑动窗口
// O(n)
// 滑动窗口:意思也就是双指针的变式,关键是确定好窗口的终止位置和起始位置。**就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。**
// 定义j确定为终止位置,当sum>target时,此时就是找到的子序列,开始移动i起始位置
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT32_MAX;
        int i = 0;  // 起始位置
        int subLength = 0;  // 滑动窗口长度即子序列长度
        int sum = 0;  // 滑动窗口数值的和
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            while (sum >= target) {
                subLength = j - i + 1;
                result = result < subLength ? result : subLength;
                sum -= nums[i];  // 滑动窗口最重要的的点,当找到子序列时,固定终止位置j,开始移动起始位置i进行判断
                i++;
            }
        }
        return result == INT32_MAX ? 0 : result;
    }
};

54. 螺旋矩阵

// 循环不变量原则,左闭右开的原则
// O(n^2)
// 模拟顺时针画矩阵的过程:
// 填充上行从左到右
// 填充右列从上到下
// 填充下行从右到左
// 填充左列从下到上
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0,starty = 0;  // 每一圈的起始位置
        int loop = n / 2;  // 循环的圈数,n=3,则loop=1
        int mid = n / 2;  // 若n为奇数,的中间位置
        int count = 1;  // 用来给每个矩阵空位置赋值
        int offset = 1;  // 需要控制每一条边遍历的长度,每次循环右边界收缩一位 即左闭右开区间
        int i, j;  // 用来行列遍历
        while (loop--) {
            i = startx;
            j = starty;
            for (j = starty; j < n - offset; j++) {  // 第一行 即最上面一行 从左到右填充 只移动列
                res[startx][j] = count++;
            }
            for (i = startx; i < n - offset; i++) {  // 最右边一列 从上到下填充 只移动行
                res[i][j] = count++;
            }
            for (;j > starty; j--) {  // 最下面一行 从右到左填充,只移动列
                res[i][j] = count++;
            }
            for (;i > startx; i--) {  // 最左侧一列 从下到上填充 只移动行
                res[i][j] = count++;
            }
            // 第二圈起始位置要改变 起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;
            offset += 1;  // offset 控制每一圈里每一条边遍历的长度
 
        }
        if (n % 2 == 1) {
                res[mid][mid] = count;
            }
        return res;
    }
};
  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值