代码随想录算法训练营第2天|LeetCode977.有序数组的平方、LeetCode209.长度最小的子数组、LeetCode:59.螺旋矩阵II

本文介绍了在LeetCode中解决的三个算法问题:有序数组的平方优化、长度最小子数组的滑动窗口算法以及螺旋矩阵II的模拟方法,通过双指针和动态规划等技巧,降低了时间复杂度至O(n)。
摘要由CSDN通过智能技术生成

代码随想录算法训练营第2天|LeetCode977.有序数组的平方、LeetCode209.长度最小的子数组、LeetCode:59.螺旋矩阵II

1、LeetCode977.有序数组的平方

题目链接:977. 有序数组的平方 - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频讲解:双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili

第一想法

直接算每一个的平方,最后sort排序。时间复杂度O(nlogn)。

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

发现平方后的数组是大小是两端大,中间小。因此可以使用两个指针从两边开始遍历,比较大小,更大的元素放入新数组并更新指针。

更新新的数组是下标从大到小即可实现新数组从小到大排序。

时间复杂度O(n)。
在这里插入图片描述

代码

注意循环条件是i<=j,若写成i<j,那么会漏掉i=j这个元素。

vector<int> sortedSquares(vector<int>& nums) {
        int size=nums.size();
        vector<int> result(size);
        // 对元素平方
        for(int i=0; i<size; i++)
            nums[i]=nums[i]*nums[i];
        
        int k = size-1;//result从最后一个开始填
        int left=0,right=size-1;
        while(left <= right){
            if(nums[left] > nums[right]){
                result[k] = nums[left++];
            }
            else{
                result[k] = nums[right--];
            }
            k--;
        }
        return result;

    }

2、LeetCode209.长度最小的子数组

题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频讲解:拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili

第一想法

两层循环,一层遍历子数组开头i,一层遍历子数组结尾j从i开始,找到sum>=target的len=j-i+1。

代码
犯错:一开始设置j=i+1,没有考虑道子序列长度为1的情况。

力扣更新了数据,暴力算法超时。

    int minSubArrayLen(int target, vector<int>& nums) {
        int maxint = 100005;
        int size=nums.size();
        int res=maxint;
        int sum=0;
        for(int i=0; i < size; i++){ //开头
            sum = 0;
            for(int j = i; j < size; j++){ //结尾
                sum += nums[j];
                int temp = j-i+1;
                if((sum == target || sum > target) && temp<res){
                    res = temp;
                    break; //后面的肯定都>=target,但是长度都不是最小
                }
            }
        }
        if(res == maxint)
            return 0;
        return res;

    }
滑动窗口解法

思路:
只用1个循环。循环的条件j指的是终止位置。当找到sum>=target的j时,移动起始位置i来找有没有更小的子序列长度len。
复杂度:
O(n)。不要以为for里放一个while就以为是O(n^2)。主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

在这里插入图片描述

重点:如何移动起始位置i。

注意:是while循环而不是if,因为是持续向后移动的过程,例如[1, 1, 1, 1, 1, 100], target为103,若为if循环,起始位置移动之后仍>=target,但已经跳出if了,该终止位置继续移动。因此应为while,起止位置持续往后移动。
在这里插入图片描述

代码:

    int minSubArrayLen(int target, vector<int>& nums) {
        int res = 100005;
        int i=0; //起始位置
        int j=0; //终止位置
        int sum=0;
        for(int j=0;j< nums.size() ; j++){
            sum += nums[j];
            while(sum > target || sum == target){
                int templen = j-i+1;
                res = templen < res ? templen : res;
                sum -= nums[i]; 
                i++; //移动起始位置
            }
        }
        if(res == 100005)
            return 0;
        return res;

    }

新的思路:
我想起来算法设计与分析课上讲的“最大子序列之和”这道题,用动态规划,从最后一个元素开始。忘了…有空回去看看…

3、LeetCode:59.螺旋矩阵II

题目链接:59. 螺旋矩阵 II - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili

面试高频,没有什么算法,单纯模拟转圈的过程。

难点:每一圈的四个顶点怎么处理,给谁处理。

思路

循环不变量:对每条边的处理规则,左闭右开,只处理第一个节点,不处理最后一个节点。

三个每圈都要更新的变量:

  • startx
  • starty
  • offset:每条边终止位置需要维护这样一个变量。

while(圈数):n/2,如果是奇数,最中间的值可以最后赋值。
在这里插入图片描述

代码

犯错

  • 二维vector定义;
  • 对上行赋值时for循环重新定义了j,导致出来后j重新变为starty,就出错了。
vector<vector<int>> generateMatrix(int n) {
        int loop = n/2;//有几圈
        int startx=0;//每一圈的起始位置
        int starty=0;
        int offset=1;
        int count=1;//用以赋值
        //二维vector定义,记得0初始化
        vector<vector<int>> ans(n,vector<int>(n, 0));
        int i,j;
        while(loop--){
            //初始化
            i = startx;
            j = starty;
            //上行
            for(j = starty; j<n-offset ; j++){     //注意!!j不能定义循环里面,这里不用重新定义j,否则出来就丢失了
                ans[startx][j] = count++;
            }
            //右边列
            for(i=startx ; i<n-offset ; i++){
                ans[i][j] = count++;
            }
            //下边行
            for( ; j > starty ; j--){
                ans[i][j] = count++;
            }
            cout<<endl;
            //左边列
            for( ; i > startx ; i--){
                ans[i][j] = count++;
            }
            // 更新
            startx++;
            starty++;
            offset++;
        }
        if(n%2 != 0){//奇数
            ans[n/2][n/2] = count;
        }
        //输出
        // for(int i=0;i<n;i++){
        //     for(int j=0;j<n;j++){
        //         cout<<ans[i][j]<<" ";
        //     }
        //     cout<<endl;
        // }

        return ans;
    }

4、总结:

  • sort排序写法sort(A.begin(), A.end())
  • vector二维数组定义方法
  • 贯穿整个代码的循环条件,不要在for里面重新定义!!
  • 45
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值