数组
977.有序数组的平方
-
题目描述
给你一个按 非递减顺序 排序的整数数组
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]
-
解题思路
本题原始数组单调递增,有正有负,平方后数组变为先减小后增大的凹型曲线。题目要求把凹曲线上的数据按照从小到大去输出。最直观的思路先遍历平方数组,找到最小值下标,写进输出数组,然后再从最小值开始同时向左向右遍历,按顺序写如输出数组。但是,这种方法需要遍历两遍数组,时间复杂度相当于O(2*n),不符合题目要求。因而需要别的方法。
对于数组来说,一开始能够获取到的下标分别为头下标和尾下标,可以先从头尾数据开始放置。由于平方数组两头大,因而只需要从新数组的末尾开始放即可。按照从大到小的顺序倒着往输出数组放即可。由于平方数组两头都大,需要比大小,因此考虑用双指针或双下标的思路来实现大小比较。
-
代码实现
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; } };
-
总结
1)数组遇到需要从两个方向同时比较的情况,考虑用双指针或双下标的方法
2)在不遍历数组的情况下能够获取数组的头尾数据,灵活运用两端的数据,正序或倒序遍历、输出数组均可。
209.长度最小的子数组
-
题目描述
给定一个含有
n
个正整数的数组和一个正整数target
。找出该数组中满足其和
≥ target
的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度**。**如果不存在符合条件的子数组,返回0
。示例 1:
输入:target = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
-
解题思路
本题需要返回子数组,子数组需要一个头下标和一个尾下标进行唯一确认,因此需要用到两个下标来遍历数组。又由于需要返回长度最小的,因而两个下标需要进行移动。进而想到滑动窗口的思路。
用一个下标指向数组起始位置,另一个下标往前走。
计算窗口内的数据和,如果大于target,可以先计算一个长度。然后让起始下标往后移动,再计算sum,如果还大于target,就可以更新长度。
-
代码实现
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; } };
-
总结
注意,在遍历数组时,是用滑窗的尾下标来遍历,依次计算窗口尾部在0,1,2.。。。位置的情况。滑动的是窗口的头下标,不断移动头下标,判断是否还满足要求。
在考虑返回值时,需要考虑如果窗口长度始终没有更新,说明没有符合条件的子数组,因而要返回0.这也是为什么初始化返回值时需要设置的比数组长度大。
-
59. 螺旋矩阵二
-
题目描述
给你一个正整数
n
,生成一个包含1
到n2
所有元素,且元素按顺时针顺序螺旋排列的n x n
正方形矩阵matrix
。示例 1:
输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]
-
解题思路
需要循环遍历正方形的四个边。在四个边的划分上,按照一致性原则,统一采用左开右闭,即第一个元素属于当前边,最后一个元素属于下一条边。用i,j表示二维数组的行列下标,按照顺序输出元素即可。
在每一个循环,矩阵的下标范围不断缩小。若n为奇数,最后一个循环只用输出一个元素。若n为 偶数,则每个循环都输出四条边。
-
代码实现
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; } };
-
总结
1)二维数组初始化采用n个一维数组的形式,一维数组初始化采用n个0的形式,一定不要写错了。
vector<vector<int>>res(n,vector<int>(n,0));
-
总结
1)二维数组初始化采用n个一维数组的形式,一维数组初始化采用n个0的形式,一定不要写错了。
vector<vector<int>>res(n,vector<int>(n,0));
2)要提前记录中间元素的坐标,否则等n-2以后,就找不到中间位置的坐标了。