训练营day02 数组 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

今日任务:day 2 第一章数组

977.有序数组的平方

题目:力扣

考点:双指针

如果采用传统思路(暴力解法),先求平方再排序,则取决于快排的时间复杂度,为O(n + nlogn)

双指针法:

动图-https://code-thinking.cdn.bcebos.com/gifs/977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.gif

建立新数组result,用k--,是因为指针i,j是从大到小的顺序去找,而新数组要求从小到大

class Solution {
public:
    vector sortedSquares(vector& nums) {
        int k = nums.size() - 1;
        vector result(nums.size(), 0);  // 新建容器,有nums.size()个元素,全部赋值为0
        for(int i=0, j=nums.size()-1; i<=j; ){
            if(nums[i]*nums[i] > nums[j]*nums[j]){
                result[k] = nums[i] * nums[i];
                i++;
                k--;
            }
            else{
                result[k] = nums[j] * nums[j];
                j--;
                k--;
            }
        }
        return result;

    }
};

209.长度最小的子数组

题目:力扣

考点:滑动窗口(还是双指针)

看文字难理解,建议看视频讲解

思路动图:https://code-thinking.cdn.bcebos.com/gifs/209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.gif

难点1:for循环中的变量指向的是滑动窗口的初始位置还是终止位置?

答:如果指向初始位置,那么终止位置只能从左到右逐渐遍历,形成当前初始位置所对应的集合,那思想上与暴力解法是一样的,所以其指向的是滑动窗口的终止位置。

所以本题的难点2是如何移动滑动窗口的初始位置

class Solution {
public:
    int minSubArrayLen(int target, vector& nums) {
        int i = 0;
        int sum = 0;
        int len = 0; 
        int result = nums.size() + 1;
        for(int j=0; j < nums.size(); j++){
            sum += nums[j];
            while(sum >= target){
                len = j - i + 1;   //因为len可能会由小变大,但我们要的是最短的长度,所以要用新变量保存
                result = len < result ? len : result;
                sum -= nums[i];
                i++;
                
            }
        }
        return result == nums.size()+1 ? 0 : result;  //为了满足没有子集符合时需返回0的情况
    }
};

问题:自己写时遇到的问题就是有了len问什么还要有result?

答:因为滑动窗口的长度len是不断变化的,而要把最短的保留下来,所以要加个变量result

最后一行是为了满足没有子集符合时需返回0的情况

问题:为什么有两个循环却是O(n)

答:因为初始位置在随着终止位置向前移动,而不是把所有的遍历了一遍,没有做重复性工作

59.螺旋矩阵II

题目:力扣

面试出现频率较高,没有什么算法,主要就是推理过程

思路:统一左闭右开、循环不变量

训练营day02 数组 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II_第1张图片

class Solution {
public:
    vector> generateMatrix(int n) {
        vector> res(n, vector(n,0));
        int xstart = 0, ystart = 0;
        int i = 0, j = 0;
        int loop = n / 2; //圈数
        int s = 1; //边界剩余
        int count = 1;
        while(loop--){
            i = xstart;
            j = ystart;
            for(j=ystart; jystart; j--)
                res[i][j] = count++;
            for(; i>xstart; i--)
                res[i][j] = count++;
            xstart++;
            ystart++;
            s++;
        }
        if(n % 2 == 1)
            res[n/2][n/2] = count;  //如果输入是1的话,前面就不会进循环,所以用i,j表示不合适
        return res;
    }
};

本章总结——数组

考察重点

二分法、双指针

基本必考,不要轻敌

各题目方法

704.二分查找:二分法,左闭右闭(更习惯)和左闭右开两种写法,left=0  right=nums.size()-1

27.移除元素:双指针法,快指针和慢指针,通向出发,快指针用于找目标元素,慢指针用于确定新数组的位置索引

977.有序数组的平方:双指针法,两指针相向而行,均是为了找平方较大的值,从大到小;新建数组,索引逐渐递减,从而实现从小到大

209.长度最小的子数组:滑动窗口法(双指针),两指针同向而行,形成滑动窗口,遍历的是终止指针,起始指针随着终止指针向前,注意求的是窗口长度变化过程中的最小值,所以要单独拿个变量保存

59.螺旋矩阵:不涉及算法,单纯模拟行为,考察代码掌控能力。利用循环不变量原则,一圈一圈的执行,每一圈分成4个方向,均采用左闭右开。

小tips

写数组时,一般用vector容器较多,求元素数量可以用.size()

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