第一章 数组

数组

977.有序数组的平方

  1. 题目描述

    给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。请你设计时间复杂度为 O(n) 的算法解决本问题。

    示例 1:

    输入:nums = [-4,-1,0,3,10]
    输出:[0,1,9,16,100]
    解释:平方后,数组变为 [16,1,0,9,100]
    排序后,数组变为 [0,1,9,16,100]
    
  2. 解题思路

    本题原始数组单调递增,有正有负,平方后数组变为先减小后增大的凹型曲线。题目要求把凹曲线上的数据按照从小到大去输出。最直观的思路先遍历平方数组,找到最小值下标,写进输出数组,然后再从最小值开始同时向左向右遍历,按顺序写如输出数组。但是,这种方法需要遍历两遍数组,时间复杂度相当于O(2*n),不符合题目要求。因而需要别的方法。

    对于数组来说,一开始能够获取到的下标分别为头下标和尾下标,可以先从头尾数据开始放置。由于平方数组两头大,因而只需要从新数组的末尾开始放即可。按照从大到小的顺序倒着往输出数组放即可。由于平方数组两头都大,需要比大小,因此考虑用双指针或双下标的思路来实现大小比较。

  3. 代码实现

    class Solution 
    {
        public:
        vector<int> sortedSquares(vector<int>& nums) {
            vector<int>res(nums.size());//存放结果
            for(int p=0,q=nums.size()-1,j=q;p<=q;)//res倒序放置,j开始指向尾
            {
                if(nums[p]*nums[p]>nums[q]*nums[q])
                {
                    res[j]=nums[p]*nums[p];//如果头比尾大,把头数据放入res中,
                    j--;//res倒序放
                    p++;//头下标往前移
                }
                else
                {
                    res[j]=nums[q]*nums[q];
                    q--;
                    j--;
                }
            }
            return res;
        }
    
    };
    
  4. 总结

    1)数组遇到需要从两个方向同时比较的情况,考虑用双指针或双下标的方法

    2)在不遍历数组的情况下能够获取数组的头尾数据,灵活运用两端的数据,正序或倒序遍历、输出数组均可。

    209.长度最小的子数组

    1. 题目描述

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

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

      示例 1:

      输入:target = 7, nums = [2,3,1,2,4,3]
      输出:2
      解释:子数组 [4,3] 是该条件下的长度最小的子数组。
      
    2. 解题思路

      本题需要返回子数组,子数组需要一个头下标和一个尾下标进行唯一确认,因此需要用到两个下标来遍历数组。又由于需要返回长度最小的,因而两个下标需要进行移动。进而想到滑动窗口的思路。

      用一个下标指向数组起始位置,另一个下标往前走。

      计算窗口内的数据和,如果大于target,可以先计算一个长度。然后让起始下标往后移动,再计算sum,如果还大于target,就可以更新长度。

    3. 代码实现

      class Solution {
      public:
          int minSubArrayLen(int target, vector<int>& nums) {
              int p=0,q=0,sum=0,ans=nums.size()+1;//初始ans给一个大于数组长度的值
              int len;
              for(q=0;q<nums.size();q++)//for遍历数组时,判断条件写<小标小于size即可,不用-1,因为小于号取不到
              {
                  sum+=nums[q];
                  while(sum>=target){
                      len=q-p+1;
                      ans=min(ans,len);
                      sum-=nums[p];
                      p++;//注意,要更新完sum以后再移动下标p
                  }
              }
              //如果ans未被更新,就返回0
              return ans==(nums.size()+1)?0:ans;
          }
      };
      
    4. 总结

      注意,在遍历数组时,是用滑窗的尾下标来遍历,依次计算窗口尾部在0,1,2.。。。位置的情况。滑动的是窗口的头下标,不断移动头下标,判断是否还满足要求。

      在考虑返回值时,需要考虑如果窗口长度始终没有更新,说明没有符合条件的子数组,因而要返回0.这也是为什么初始化返回值时需要设置的比数组长度大。

59. 螺旋矩阵二

  1. 题目描述

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

    示例 1:

    img

    输入:n = 3
    输出:[[1,2,3],[8,9,4],[7,6,5]]
    
  2. 解题思路

    需要循环遍历正方形的四个边。在四个边的划分上,按照一致性原则,统一采用左开右闭,即第一个元素属于当前边,最后一个元素属于下一条边。用i,j表示二维数组的行列下标,按照顺序输出元素即可。

    在每一个循环,矩阵的下标范围不断缩小。若n为奇数,最后一个循环只用输出一个元素。若n为 偶数,则每个循环都输出四条边。

  3. 代码实现

    class Solution {
    public:
        vector<vector<int>> generateMatrix(int n) {
            int top=0,bottom=n-1,left=0,right=n-1,out=1;
            vector<vector<int>>res(n,vector<int>(n,0));
            int mid=n/2;//中间位置坐标要提前留出来
            while(n/2)
            {
                //遍历第一条边
                for(int j=left;j<right;j++){
                    res[top][j]=out;
                    out++;
                }
                //遍历第二条边
                for(int i=top;i<bottom;i++){
                    res[i][right]=out;
                    out++;
                }
                //遍历第三条边,倒序
                for(int j=right;j>left;j--){
                    res[bottom][j]=out;
                    out++;
                }
                //遍历第四条边,倒序
                for(int i=bottom;i>top;i--){
                    res[i][left]=out;
                    out++;
                }
                top++;
                right--;
                bottom--;
                left++;
                n=n-2;
            }
        if(n==1){
            res[mid][mid]=out;
        }
        return res;
        }
    };
    
  4. 总结

    1)二维数组初始化采用n个一维数组的形式,一维数组初始化采用n个0的形式,一定不要写错了。

    vector<vector<int>>res(n,vector<int>(n,0));
    
  5. 总结

    1)二维数组初始化采用n个一维数组的形式,一维数组初始化采用n个0的形式,一定不要写错了。

    vector<vector<int>>res(n,vector<int>(n,0));
    

​ 2)要提前记录中间元素的坐标,否则等n-2以后,就找不到中间位置的坐标了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值