刷题记录day2|977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II ,总结

977、有序数组的平方

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

方法1:暴力

直接排序,sort的时间复杂度O(nlogn)
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> vec;
        for(int i = 0;i<nums.size();i++){
            vec.emplace_back(nums[i]*nums[i]);
        }
        sort(vec.begin(),vec.end());
        return vec;
    }
};

方法2:双指针

由于是有序数组,所以平方之后,一定是两边的大中间的小,所以要比较两边的元素大小,在从大到小倒序填入到数组之中即可,时间复杂度为O(n)即可实现

注意:这里的左右指针一定是可以相等的,不然就丢失了最后一个数据。还有这个在数组中倒序添加元素的方法也要注意。
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {     
        int right = nums.size()-1;
        int  k = nums.size()-1;
        int left = 0;
        vector<int> ans(nums.size(),0);
        while(left<=right){
            if(nums[left]*nums[left]>=nums[right]*nums[right]){
                ans[k] = nums[left]*nums[left];
                k--;
                left++;
            }else {
                ans[k] = nums[right]*nums[right];
                k--;
                right--;
            }
        }
        return ans;
    }
};

209、长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

209长度最小的子数组

滑动窗口

滑动窗口时间复杂度是O(n),而不是O(n^2)

左右两个指针,右指针移动,sum记录元素和,当元素和大于等于目标值时,就要通过左指针右移实现窗口减小,同时sum要减去那个元素的值,记录最小的结果,这里不是只做一次判断,而是要多次判断,如果左指针移动一位后,还是不满足条件就要接着左移来缩小窗口,所以是while而不是if。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        //if(n == 0)return 0;
        int left = 0,right = 0;
        int sum = 0,ans = INT_MAX;
        while(right<n){
            sum +=nums[right];
            while(sum>=target){
                ans = min(ans,right-left+1);
                sum-=nums[left];
                left++;
            }
            right++;
        }
        return ans ==INT_MAX ?0:ans;
    }
};

59.螺旋矩阵II

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

59螺旋矩阵

模拟:一开始从左往右填充,填完之后就不在调整第一行,up++

        接着在右边从上往下填充,填完之后,最右侧那一列就不再动,right--

        在底边从右向左填充,填完之后,最下面那一行不再动,down--

        在左边从下往上填充,填完之后,最左边那一列不再动,left++

        由此就将第一圈全部填充完毕,再继续缩小范围,知道数字达到目标值就结束

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> ans(n,vector<int>(n,0));
        int left = 0,right = n-1;
        int up = 0,down = n-1;
        int count = 1,target = n*n; 
        //for循环中变量定义成i或j的细节:按照通常的思维,i代表行,j代表列
        //这样,就可以很容易区分出来变化的量应该放在[][]的第一个还是第二个
        //对于变量的边界怎么定义:
            //从左向右填充:填充的列肯定在[left,right]区间
            //从上向下填充:填充的行肯定在[up,down]区间
            //从右向左填充:填充的列肯定在[right,left]区间
            //从下向上填充:填充的行肯定在[down,up]区间
        //通过上面的总结会发现边界的起始和结束与方向是对应的
        while(count<=target){
            //从左向右填充
            for(int i = left;i<=right;i++){
                ans[up][i] = count;
                count++;
            }
            //缩小上边界
            up++;
            //从上往下填充
            for(int i = up;i<=down;i++){
                ans[i][right] = count;
                count++;
            }
            //缩小右边界
            right--;
            //从右往左填充
            for(int i = right;i>=left;i--){
                ans[down][i] = count;
                count++;
            }
            //缩小下边界
            down--;
            //从下往上填充
            for(int i = down;i>=up;i--){
                ans[i][left] = count;
                count++;
            }
            //缩小左边界
            left++;
        }
        return ans;
    }
};

总结

数组经典题目:二分,双指针,滑动窗口,模拟

二分法:

                左闭右闭

                左闭右开

双指针:

                都从左开始移动的双指针

                一左一右的双指针

滑动窗口:

                时间复杂度O(n)

模拟:

                注意边界值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值