题目:977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II
参考链接:代码随想录
977.有序数组的平方
思路:首先是暴力算法,先平方再排序,排序可以直接使用sort(),默认为快速排序,复杂度为O(nlogn)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len=nums.size();
for(int i=0;i<len;i++){
nums[i]=nums[i]*nums[i];
}
sort(nums.begin(),nums.end());
return nums;
}
};
然后是双指针法,即两个指针分别指向数组首尾,因为返回结果的最大值必定是从两边到中间,我们先定义一个结果数组ans。双指针每次遍历原数组时比较平方大小,大的则填写到ans的末尾,依次往前填充。复杂度O(n)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len=nums.size();
vector<int> ans(len,0);//初始化长度一样,开始全部置0
int left=0,right=len-1,k=len-1;
int tmp1,tmp2;
while(left<=right && k>=0){
tmp1=nums[left]*nums[left];
tmp2=nums[right]*nums[right];
if(tmp1>=tmp2){
ans[k--]=tmp1;
left++;
}
else{
ans[k--]=tmp2;
right--;
}
}
return ans;
}
};
运行结束后发现,时间为22ms,而暴力算法的时间为24ms,与标答对比,发现自己多定义了两个tmp,以及len,可能会导致力扣时间变长?然后while中的k>=0其实不需要,因为当双指针遍历完后必定恰好填满ans数组。
标答:
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
int k = A.size() - 1;
vector<int> result(A.size(), 0);
for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
if (A[i] * A[i] < A[j] * A[j]) {
result[k--] = A[j] * A[j];
j--;
}
else {
result[k--] = A[i] * A[i];
i++;
}
}
return result;
}
};
当然运行标答也只有20ms,基本没提升,所以力扣的运行时间看一乐就行。
209.长度最小的子数组
思路:首先想到暴力算法,即对nums中每一个元素,从其开始往后遍历,寻找和为target的子数组,这样的时间复杂度为O(n^2)。
滑动窗口算法:采用两个指针i和j,分别指向窗口头尾,for循环中使用j来遍历nums,对i的确定,可以这么看,由于nums都为正整数,如果目前窗口的和小于target,说明窗口需要扩大,则移动j,如果和大于等于target,说明窗口需要缩小,则移动i。这样复杂度O(n)
一开始错误代码:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int len=nums.size();
int i,j,n=len+1,ans=0,anslength;//n为最小子数组长度,初始化为len+1,ans为窗口的和
for(i=0,j=0;j<len;j++){
ans+=nums[j];
//在一次for循环中,只移动i
while(ans>=target){
if(ans==target){//找到了子数组
anslength=j-i+1;
n=anslength<n ? anslength : n;
}
ans-=nums[i++];
}
}
if(n!=len+1){
return n;
}
return 0;
}
};
发现自己一开始把题目看错了,题目是大于等于target,我看成了等于。去掉if就对了:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int len=nums.size();
int i,j,n=len+1,ans=0,anslength;//n为最小子数组长度,初始化为len+1,ans为窗口的和
for(i=0,j=0;j<len;j++){
ans+=nums[j];
//在一次for循环中,只移动i
while(ans>=target){
anslength=j-i+1;
n=anslength<n ? anslength : n;
ans-=nums[i++];
}
}
if(n!=len+1){
return n;
}
return 0;
}
};
本题的精髓在于while中的写法,滑动窗口左侧移动i,使得sum减小,一旦低于target则跳出while,移动j,又增大sum。标答中将n设置为INT32_MAX,也是一样的效果。
59.螺旋矩阵II
思路:本题我看到第一次想到的是分类讨论,将n为奇数和偶数分开讨论,当n为奇数的时候,设n=2k+1,这时候可以把矩阵分为k=1,k=2...这k次来遍历。当n为偶数的时候,设n=2k,同样是循环k次来遍历。例如n=4,k=2的遍历为123->456->789->101112,k=1的遍历为13->14->15->16,对k的一次循环则分4次进行,对四个边分别遍历k次。
一开始没写出来的代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> mat(n, vector<int>(n, 0));
int k;
int count=1;
if(n%2==1){//n为奇数
k=n/2;
for(int s=k;s>0;s--){//对k反着遍历,每次循环填充4*(2k)个,s表示循环轮数
for(int t=0;t<2*s;t++){
mat[][]=count++;
mat[][]=count++;
mat[][]=count++;
mat[][]=count++;
}
}
}
else{
}
}
};
看了解析后发现自己思路其实整体并没多大问题,主要是具体代码实现上,首先变量命名可以使用一点带有意义的单词比如loop,然后本题主要我没写出来的地方是对于每一个loop的遍历,需要分为四个for循环来写,我妄图一个for搞定四次,最后把自己搞混了也没写出来。
本题其实并没有设计什么深奥的算法,主要是对循环不变量的理解。
看完解析后自己写的结果:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> mat(n, vector<int>(n, 0));
int i,j;
int count=1;
int loop=n/2;
int mid=n/2;//n为奇数的时候单独处理一下
int startx=0,starty=0;//每次开始循环时的起始位置
int offset;
for(;loop>0;loop--){
i=startx;
j=starty;
offset=n/2+1-loop;//偏移量,每次循环都要加一
for(i=startx;i<n-offset;i++){//左开右闭
mat[i][j]=count++;
}
for(j=starty;j<n-offset;j++){
mat[i][j]=count++;
}
for(i=n-offset;i>startx;i--){
mat[i][j]=count++;
}
for(j=n-offset;i>starty;j--){
mat[i][j]=count++;
}
startx++;
starty++;
}
if(n%2==1){
mat[mid][mid]=count;
}
return mat;
}
};
依旧报错,错误出在写for循环时将i和j搞混,实际上一开始从左到右是遍历的j,我搞成了i,导致结果错误。说明细节十分重要。
再一次修改终于成功:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> mat(n, vector<int>(n, 0));
int i,j;
int count=1;
int loop=n/2;
int mid=n/2;//n为奇数的时候单独处理一下
int startx=0,starty=0;//每次开始循环时的起始位置
int offset;
for(;loop>0;loop--){
i=startx;
j=starty;
offset=n/2+1-loop;//偏移量,每次循环都要加一
for(j=starty;j<n-offset;j++){
mat[i][j]=count++;
}
for(i=startx;i<n-offset;i++){//左开右闭
mat[i][j]=count++;
}
for(j=n-offset;j>starty;j--){
mat[i][j]=count++;
}
for(i=n-offset;i>startx;i--){
mat[i][j]=count++;
}
startx++;
starty++;
}
if(n%2==1){
mat[mid][mid]=count;
}
return mat;
}
};