数组part02
一、有序数组的平方
法一:暴力,先把每个元素平方再排序,时间复杂度O(n + nlogn)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i=0;i<nums.size();i++) nums[i]*=nums[i];
sort(nums.begin(),nums.end());
return nums;
}
};
法二:双指针,时间复杂度O(n)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int k=nums.size()-1;
vector<int> res(nums.size(),0);
for(int i=0,j=nums.size()-1;i<=j;)
{
if(nums[i]*nums[i]<nums[j]*nums[j])
{
res[k--]=nums[j]*nums[j];
j--;
}
else
{
res[k--]=nums[i]*nums[i];
i++;
}
}
return res;
}
};
二、长度最小的子数组
法一:暴力,时间复杂度:O(n^2),空间复杂度:O(1)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int res=INT32_MAX; // 最终结果
int sum=0; // 子序列的数值之和
int subLength=0; // 子序列长度
for(int i=0;i<nums.size();i++)
{
sum=0;
for(int j=i;j<nums.size();j++)
{
sum+=nums[j];
if(sum>=target)
{
subLength=j-i+1;
res=res<subLength?res:subLength;
break;
}
}
}
return res==INT32_MAX?0:res;
}
};
法二:滑动窗口,时间复杂度:O(n),空间复杂度:O(1)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int res=INT32_MAX;
int i=0; // 滑动窗口起始位置
int sum=0; // 窗口内元素的和
for(int j=0;j<nums.size();j++)
{
sum+=nums[j];
while(sum>=target)
{
int subLength=j-i+1; // 取子序列长度
res=res<subLength?res:subLength;
sum=sum-nums[i];
i++; // 更新i,以保证取的长度最小
}
}
return res==INT32_MAX?0:res;
}
};
为什么时间复杂度是O(n)。
不是for里放一个while就是O(n^2), 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
三、螺旋矩阵II
类似二分的思想,控制循环不变量,维护的区间始终为左闭右开
时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
空间复杂度 O(1)
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0)); // 初始化一个二维数组
int startx=0,starty=0; // 定义每循环一个圈的起始位置
int loop=n/2; // 有几个圈
int mid=n/2; // n为奇数时的矩阵的中间位置
int offset=1; // 需要控制每条边的遍历长度,每循环一圈右边界就收缩一位
int count=1; // 用来给矩阵中每一个空格赋值
int i,j;
while(loop--)
{
i=startx;
j=starty;
// 下面四个for循环就是模拟转了一圈
// 模拟填充上行从左到右(左闭右开)
for(;j<n-offset;j++) res[i][j]=count++;
// 模拟填充右列从上到下(左闭右开)
for(;i<n-offset;i++) res[i][j]=count++;
// 模拟填充下行从右到左(左闭右开)
for(;j>startx;j--) res[i][j]=count++;
// 模拟填充左列从下到上(左闭右开)
for(;i>startx;i--) res[i][j]=count++;
// 下一圈开始后,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startx++;
starty++;
// offset 控制每一圈里每一条边遍历的长度
offset++;
}
// 若n为奇数,最后还需要给矩阵的中心单独赋值
if(n%2) res[mid][mid]=count;
return res;
}
};