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

Leetcode 977.有序数组的平方

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

题干:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

思考一:双指针法,借鉴归并的思想,用空间换时间。考虑到大的值一定在数组的两端,用两个指针分别指向首尾下标,将较大值放入结果数组中并移动对应的指针。

代码:

class Solution {
public:
    vector sortedSquares(vector& nums) {
        int n = nums.size();
        int k = n - 1;      //从尾部向前存储
        vector result(n);
        for(int i = 0, j = n -1; i <= j;) {
            if(nums[i] * nums[i] > nums[j] * nums[j]) {     //将大的值写入结果数组中并移动指针
                result[k--] = nums[i] * nums[i];
                i++;
            } else {
                result[k--] = nums[j] * nums[j];
                j--;
            }
        }
        return result;
    }
};

思考二:暴力法,先处理平方,再调库函数sort(底层思想:快速排序)处理顺序

代码:

class Solution {
public:
    vector sortedSquares(vector& A) {
        for (int i = 0; i < A.size(); i++) {
            A[i] *= A[i];
        }
        sort(A.begin(), A.end()); // 快速排序
        return A;
    }
};

Leetcode 209.长度最小的子数组

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

题干:给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

思考:双指针法,也叫滑动窗口。

  • 快指针:用来向后寻找区间总和大于目标值后面的下标
  • 慢指针:在满足区间总和大于目标值的前提下缩小区间长度,获取最短长度

代码(写法一):

class Solution {
public:
    int minSubArrayLen(int target, vector& 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 >= target) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

代码(写法二,思想一样但超时,在处理区间长度缩减时花费更多时长):

class Solution {
public:
    int minSubArrayLen(int target, vector& nums) {
        int i = 0, j = 0;
        int length = INT32_MAX; //记录最短长度
        int sum = nums[0];
        while (j < nums.size()) {
            if (sum >= target) {//满足总和大的条件
                length = length > j - i + 1 ? j - i + 1 : length;       //记录较小长度
                sum -= nums[i++];       //窗口减小
            } else {//后面指针后移
                sum += nums[++j];
            }
        }
        return length == INT32_MAX ? 0 : length;
    }
};

Leetcode 59.螺旋矩阵II

题目链接:59 螺旋矩阵II

题干:给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

思考:将问题细分成处理每一圈的数据,每层循环考虑左到右、上到下、右到左、下到上的情况,处理好每一圈数据要修改下次起始的坐标位置、每条边处理数据的个数以及记录处理圈数。最后如果n是奇数,矩阵中央位置的元素单独赋值。

  • 注意:圈数为n/2。理由:要得到的矩阵边为n,每处理一圈边减二(处理完的一圈去除后再看边长度)

代码:

class Solution {
public:
    vector> generateMatrix(int n) {
        vector> nums(n, vector(n, 0));
        int i, j;       //横坐标纵坐标
        int startX = 0, startY = 0;     //每圈起始位置
        int len = n - 1;     //每圈每条边处理数据的长度
        int laps = n / 2;       //处理圈数
        int count = 1;      //赋值
        while (laps > 0) {
            i = startX;
            j = startY;

            //处理每一圈
            for (; j < len; j++)        //左到右
                nums[i][j] = count++;
            for (; i < len; i++)        //上到下
                nums[i][j] = count++;
            for (; j > startY; j--)     //右到左
                nums[i][j] = count++;
            for (; i > startX; i--)     //下到上
                nums[i][j] = count++;
            
            //每圈的处理
            startX++;
            startY++;
            len--;
            laps--;
        }

        //n为奇数单独处理中间元素
        if (n % 2 == 1) {
            int middle = n / 2;
            nums[middle][middle] = count;
        }
        return nums; 
    }
};

数组专题的总结:

  • 双指针法的重新理解,活用两个指针来降低时间复杂度。考虑两个指针指向含义以及每次指针移动的含义,最后考虑好结束标志与两个指针的关系
  • 了解滑动窗口,双指针法的另一种形式应用。两指针一静一动,快指针用来寻找满足条件的位置,满指针用来寻找在满足条件的前提下的极限值
  • 加强拆分的思想,细化大问题,关键在于寻找怎样将大问题转化为操作一致的一次或多次操作以及循环的次数

你可能感兴趣的:(代码随想录算法训练营,算法,leetcode)