有序数组的平方
文档讲解:代码随想录
视频讲解:LeetCode:977.有序数组的平方
状态:能做
- 思路
之后刷的时候用各种排序算法写一下。
主要还是利用双指针,考虑到负数和正数,在平方后可能出现大小颠倒的情况,所以需要寻找一个分割线,然后利用两个指针来判断两段中的数的大小,较小的填入返回数组,并移动下标。
分割线就是第一个不小于0的数。但这种方法还需要注意全是负数的情况
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//获取第一个大于等于0的数
int middle = -1;
for(int i=0;i<nums.size();i++)
{
if(nums[i]>=0)
{
middle = i;
break;
}
}
//判断全是负数的情况,最终结果是倒序
if(middle == -1)
{
middle = nums.size();
}
//定义两个指针,一个从最大的负数开始middle-1,一个从最小的非负数开始middle
int pt1 = middle-1;
int pt2 = middle;
//当pt1>=0并且pt2<size的时候进行判断,并填入返回的数组
//当有一个超出了限制,则将剩下的另一个全部填入数组依序。
vector<int> res(nums.size());
int k = 0;
while(pt1>=0&&pt2<nums.size())
{
if(nums[pt1]*nums[pt1] > nums[pt2]*nums[pt2])
{
res[k] = nums[pt2]*nums[pt2];
k++;
pt2++;
}
else
{
res[k] = nums[pt1]*nums[pt1];
k++;
pt1--;
}
}
//将剩下的填入
while(pt1>=0)
{
res[k] = nums[pt1]*nums[pt1];
k++;
pt1--;
}
while(pt2<nums.size())
{
res[k] = nums[pt2]*nums[pt2];
k++;
pt2++;
}
return res;
}
};
- 代码随想录方法
利用头指针和尾指针向中间收缩,注意两头的值肯定是平方后的最大值,所以返回数组的填写需要通过倒序填写。并且循环处理的终止条件是左指针大于右指针,因为两个指针同时指向的值也需要填入,一般为最小值。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> res(nums.size());
int left = 0;
int right = nums.size()-1;
int k = nums.size()-1;
for(left,right;left<=right;)
{
if(nums[left]*nums[left]>=nums[right]*nums[right])
{
res[k] = nums[left]*nums[left];
k--;
left++;
}
else
{
res[k] = nums[right]*nums[right];
k--;
right--;
}
}
return res;
}
};
长度最小的子数组
文档讲解:代码随想录
视频讲解:拿下滑动窗口! | LeetCode 209 长度最小的子数组
状态:85%
- 思路
连续子数组,相当于用一个子数组去框选长度最小满足条件的范围,首先确定头和尾就使用两个指针,当和一直小于target那么就移动尾指针,如果和大于等于target后就向前移动头指针,并减去之前的头指针指向的位置。
之前我的写法没有用while判断,导致头尾指针的移动在一起(错误),减枝不好处理。后来学习过后,利用while处理头指针的移动,使得头尾指针的移动能够分开来进行。
当和一直大于等于target移动头指针,当和小于target移动尾指针
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
//数组长度记录
int count = 0;
//头指针,当sum>=target时移动
int left = 0;
//尾指针,当sum<target时移动
int right = 0;
//和,当小于target时由right控制,大于等于targte时由left控制
int sum = 0;
while(right<nums.size())
{
sum += nums[right];
while(sum>=target)
{
if(count > right-left+1 || count == 0)
{
count = right-left+1;
}
sum -= nums[left++];
}
right++;
}
return count;
}
};
螺旋矩阵II
文档讲解:代码随想录
视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II
状态:不会
- 思路
一个螺旋就是一个循环,从外层向里依次填入数据。主要需要思考的问题有以下几点- 循环的次数:n/2
- 新循环的起点:最开始是0,0,循环一次后是1,1,所以需要每次循环完进行+1操作
- 每次循环每条边的填充长度控制:最开始是n-1个位置都需要填,第二次是n-2,所以每次循环完之后进行-1操作
- 奇数n的中间数操作:对于奇数n,中间数一定是他的平方数,而对于偶数n不存在,所以利用mod2来判断是否是奇数
- 填充操作:首先要注意不能重复填充,特别是每层循环的4个角位置,如果我们对填充操作的边界是<=或者>=那么肯定会出现重叠,所以应该选择左闭右开的方式来进行填充。其次是每次填充由右向左进行填写时,注意边界,应当是当前的起点坐标对应的x,y值。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
//0,0 -> 0,n-1 [0,n-1) ->
//0,n-1 -> n-1,n-1 [0,n-1) ⬇
//n-1,n-1 -> n-1,0 [n-1,0) <-
//n-1,0 -> 0,0 [n-1,0) ⬆
int size = n-1;
vector<vector<int>> res(n,vector<int>(n));
//起始位置
int numx = 0;
int numy = 0;
//填充循环数
int loop = n/2;
//填充数
int i = 1;
//每条边的长度控制
int k = 1;
while(loop--)
{
//每条边的填入位置控制
int a = numx;
int b = numy;
//-> x=0 , y[0,n-1)
for(b;b<n-k;b++)
{
res[a][b] = i++;
}
//⬇ y=n-1 , x[0,n-1)
for(a;a<n-k;a++)
{
res[a][b] = i++;
}
//<- x=n-1 , y[n-1,0)
for(b;b>numx;b--)
{
res[a][b] = i++;
}
//⬆ y=0 , x=[n-1,0)
for(a;a>numy;a--)
{
res[a][b] = i++;
}
//一层做完,更新起始位置和循环边的长度
numx++;
numy++;
k++;
}
//考虑n为奇数,那么最中间的数就是n²
if(n%2)
{
res[n/2][n/2] = n*n;
}
return res;
}
};
时间复杂度:k(n-1+n-2+…+1) = O( n 2 n^2 n2)
螺旋矩阵
- 思路
本题和上一题相似,具体两点区别- 一个是二维变一维,一个是一维变二维
- 这道题的边长不相等了。
第一个变化很容易解决,就是在循环中把赋值操作换一下,第二点就需要更多的判断了以及设计到循环次数的控制。
使用m/2和n/2较小的数作为循环次数,这样在循环完成之后,只会剩下1列或者1行,直接读入就可以了。其次在最后读入的时候还需要考虑现在是不是已经读取完毕了,比如对于3行2列的情况,在1次循环过程中已经可以满足所有的数据读入。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
//行数
int m = matrix.size();
//列数
int n = matrix[0].size();
int loop = m<n?m/2:n/2;
//返回数组
int k = 0;
vector<int> res(m*n);
//循环读取
int numx = 0;
int numy = 0;
int check = 1;
while(loop--)
{
int i = numy;
int j = numx;
//-> i=0 j[0,n-1)
for(j;j<n-check;j++)
{
res[k++] = matrix[i][j];
}
//⬇ j=m-1 i[0,m-1)
for(i;i<m-check;i++)
{
res[k++] = matrix[i][j];
}
//<- i=m-1 j[n-1,0)
for(j;j>numy;j--)
{
res[k++] = matrix[i][j];
}
//⬆ j = 0, i[n-1,0)
for(i;i>numx;i--)
{
res[k++] = matrix[i][j];
}
numx++;
numy++;
check++;
}
//正方形奇数矩阵,读取最后一个数
if(m==n && m%2)
{
res[k] = matrix[m/2][n/2];
}
//其他普通矩阵,读取剩余的列(行数为m/2)或者行(列数为n/2)
//需要注意的是,目前应当采用[]区间,因为要获得最后一个数
//具体的逻辑,可以考虑如何读取只有1行或者1列的方法。
if(m>n)
{
for(int i=numx;i<=m-check;i++)
{
if(k<m*n){
res[k++] = matrix[i][n/2];
}
}
}
if(m<n)
{
for(int j = numy;j<=n-check;j++)
{
if(k<m*n)
{
res[k++] = matrix[m/2][j];
}
}
}
return res;
}
};