【Day2 数组】977有序数组的平方,209长度最小的子数组,59螺旋矩阵II 思路和易错点归纳 | 代码随想录算法训练营

👉学习内容:977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

做题建议:先独立做题,然后看视频讲解,然后看文章讲解,然后在重新做一遍题,把题目AC,最后整理成今日当天的博客

一、力扣第977题有序数组的平方(文章链接 视频链接

我的思路:只想到把负数找出来变成相反数,排序后再平方,排序用双指针。但是这样和平方后排序其实没有什么改进,复杂度还是而很大。

本题思路:由于本题有序排列,平方后首尾两端为整个数组最大的,形成“大小大”的结构。所以,为了减少复杂度,可以两个指针直接比较首尾两端的值得到数组最大的值,再继续循环比较首尾两端,直到得到一个排序的新数组。
在这里插入图片描述

自己手敲错误记录:

  • 【数组忘记定义】定义一个新数组result,与nums同长度,设所有元素为0 :vector result(nums.size(), 0);
  • 【for的语句用法为定义变量;判断;操作】分号不能乱用,不能写成“int i=0 ; int j=nums.size()-1;” 且也不能写成“int i=0,int j =nums.size()-1;”
  • 又忘记写返回值return(返回数组只写数组名即可)。
  • 一开始定义的数组名称叫"new",与变量冲突报错。

本题语法特殊点:

  • 此处的i++和j–由于只能操作一个,且依据实际情况左右两端谁大,所以不能写在括号里可以不写(c++中),但是判断句“i<=j”后面的分号还要写。
  • "result[k]=xxxx;k–;"可以简写为“result[k–]=xxxx;”

小总结:

  • 代码开不了头时,一般为定义个变量,开始for循环,先写着。
  • 好的解法复杂度不会高。想要找到好的思路,就要考虑到每题的特殊性,或者怎么利用一些已有的条件去简化算法操作流程,比如本题可以提前判断出来两头最大,就不需要再让算法一个一个对比找到最大的数。

本题解答

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int k= nums.size() -1;
        vector<int> result(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[j]*nums[j];
                j--;
            }
            else{
                result[k--]=nums[i]*nums[i];
                i++;
            }
        }
        return result;

    }
};

二、力扣第209题长度最小的子数组(文章链接 视频链接

我的思路:没有思路,感觉乱七八糟,c++语法薄弱。

本题思路:滑动窗口思想,前提本题是有序数组。图解参考代码随想录上述文章链接处。

自己手敲错误记录:

  • 【while用法】
    问题:纠结while循环第一次后时出去执行for的"j++“还是whlie的判断"sum>s”?
    例如:
    [1 2 4 5],s=4,则第一次应该是比较得到长度3,[1 2 4]>4;第二次是2,[2 4]>4。
    但是如果执行的是for的j++,则j+1向右移动一位,得到了3 [2 4 5]>4,错误。

while 循环执行逻辑:
只要循环成立条件为真,就进入循环体
重复这个步骤,直到循环成立条件为假

	💡事实上是while的语法不清晰,参考上述逻辑就清楚为什么题解在得到result长度值后,立刻写一句“sum -= nums[i++];”
	因为此时得到了一个新的sum,对于本例来说新的sum(此时只向右移动了i,为[2 4])仍然在循环条件"while (sum >= s)"内,
	那么就可以继续执行while循环体,直到不满足了才出去执行j++。
  • 新的变量总是忘记先int定义。

本题语法特殊点:

  • 使用while语句而不是if语句,为了能够持续的执行for循环,而不至于if判断不成立后直接结束。
  • for语句的索引j代表终止位置,减少算法计算量,否则和暴力解法无异(待补充)。

小总结:

  • 关于复杂度:不要见到两个循环嵌套就以为时间复杂度是O(n^2),时间复杂度主要是看每一个元素被操作的次数,每个元素在滑动窗口往右扩大时进来一次,窗口缩小时出去一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
  • “滑动窗口本质上也是一种双指针法,是在充分理解题目的情况下,暴力算法的一种简化。这道题之所以可以使用滑动窗口,很重要的一个原因是,在移动终止位置的时候,初始位置是不可逆的,初始位置只可能往后移动,而不用每次都从第零个元素开始。所有双指针法,都是充分利用题目的一个隐藏的特征,来对暴力算法的一种简化。”

本题解答

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result= INT32_MAX;
        int sum =0;
        int i=0;
        int newlenth =0;
        for(int j=0;j<nums.size();j++){
            sum +=nums[j];
            while(sum >= target){
                newlenth=(j-i+1);
                result=min(result,newlenth);
                sum -= nums[i++];
            }
        }
        return result == INT32_MAX ? 0 : result;//不懂这句什么意思
    }
};

三、力扣第59题螺旋矩阵II (文章链接 视频链接

我的思路:看错了题目^ - ^,笑,还一本正经画了个图
在这里插入图片描述

本题思路:结合二分查找的循环不变量原则,在每次for循环的时候,需要采用共同的规则(左闭右开)来控制边界,以防元素溢出或混乱。

自己手敲错误记录:

  • (待补充)

本题特殊点:

  • 弄清楚每条边循环起始位置及结果的数组表达方式
  • 由于是个圈,所以从哪开始绕都能闭合,初始值自定义(startx,starty)

小总结:

  • 先找规律:圈数一定是n/2,因为绕一圈走两行
  • 中心点(如果n为奇数)一定是(n/2,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为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            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 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

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

数组总结

  • 图源知识星球@海螺人
    在这里插入图片描述
  • 17
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值