LeetCode977. 有序数组的平方
题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
思路:看到题目的第一想法是使用暴力法:数组里的每个元素都平方一下,再排个序。
C++代码如下:
class Solution
{
public:
vector<int> sortedSquares(vector<int>& nums)
{
for(int i = 0; i < nums.size(); i++)
{
nums[i] = nums[i]*nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
思考:可以使用双指针法。题目说了数组是有序的,那么该数组平方的最大值就在数组的两端,要么最左边,要么最右边,不可能在中间。
考虑用双指针法,i指向原数组起始位置,j指向原数组终止位置。
再定义一个新的数组,用于存放最终结果,和原数组一样的大小。
如果A[i]*A[i] ≤ A[j]*A[j],那么result[k] = A[j]*A[j],k- -,j- -;
如果A[i]*A[i] > A[j]*A[j],那么result[k] = A[i]*A[i],k- -,i++;
![](https://i-blog.csdnimg.cn/blog_migrate/cd39219d6ba2b3988e7702324ce0d36f.png)
C++代码如下:
class Solution
{
public:
vector<int> sortedSquares(vector<int>& nums)
{
vector<int> A(nums.size(), 0); //最后的结果存放在这个新数组中
int i = 0;
int j = nums.size() - 1;
int len = nums.size() - 1;
while(i < j)
{
if((nums[i]*nums[i]) <= (nums[j]*nums[j]))
{
A[len] = nums[j]*nums[j];
len--;
j--;
}
else if((nums[i] * nums[i]) > (nums[j] * nums[j]))
{
A[len] = nums[i]* nums[i];
len--;
i++;
}
}
A[0] = nums[i] * nums[i];
return A;
}
};
LeetCode209. 长度最小的子数组
题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
思路:暴力法,用两层for循环,不断寻找符合条件的子序列,再找出长度最短的子序列。时间复杂度:O(n^2)。
C++代码如下:
class Solution
{
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int result = INT32_MAX; //最终的结果
int sum = 0; //子序列的数值之和
int subLength = 0; //子序列的长度
for(int i = 0; i < nums.size(); i++) //设置子序列起点为i
{
sum = 0;
for(int j = i; j < nums.size(); j++) //设置子序列终点位置为j
{
sum += nums[j];
if(sum >= target) //若子序列之和超过target,更新result
{
subLength = j - i + 1; //子序列长度
result = result < subLength ? result : subLength;
break; //因为找的是符合条件的最短的子序列,所以符合条件后子序列没必要继续累加了。所以弹出该循环去更新子序列的起点找新的符合条件的子序列。
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
思考:
使用滑动窗口,其实我把它也理解成是双指针法(快慢指针法)。
在上面的暴力法中,是一个for循环为滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环完成了一个不断搜索区间的过程。
我用双指针法在一个for循环下完成两个for循环的工作。
定义快慢指针
快指针:指向子序列的终点位置
慢指针:指向子序列的起始位置
每次fastIndex移动时,都会把子序列的数值累加起来与target比较,若小于target,则进入下一个循环,fastIndex继续移动,寻找符合条件的子序列;
当子序列的数值累加后大于等于target,即符合条件,计算当前子序列的长度,并与result比较,把较小的更新为最新的result。更新result之后子序列数值之和还要减去slowIndex指向的数值,并向前移动slowIndex,因为我们要寻找符合条件的最短的子序列:1.如果不移动slowIndex而是继续移动fastIndex,就没必要了,因为后面的子序列肯定比当前的要长;2.同时,有可能减去当前slowIndex指向的数值后的子序列仍旧符合条件,所以,在找到符合条件的子序列后要移动slowIndex,更新子序列再继续判断是否符合条件。
C++代码如下:
class Solution
{
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int sum = 0; //子序列元素之和
int slowIndex = 0;
int fastIndex = 0;
int subLength = 0; //子序列长度
int result = INT32_MAX;
for(fastIndex = 0; fastIndex < nums.size(); fastIndex++)
{
sum += nums[fastIndex];
while(sum >= target)
{
subLength = fastIndex - slowIndex + 1;
result = result < subLength ? result : subLength;
sum -= nums[slowIndex];
slowIndex++;
}
if((fastIndex==nums.size()-1)&&(slowIndex==0)&&(sum < target)) //如果整个数组都加起来也小于target,则直接返回0。
{
result = 0;
}
}
return result;
}
};
LeetCode59. 螺旋矩阵II
题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
思路:一开始的想法是把n=1~5全部列出来,再找规律,但是后来没有写出来。现做法就是模拟过程,一步一步写出来。
模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
由外向内一圈圈画下去。
代码中画的每一条边,都按照左闭右开的原则:
这里每一种颜色,代表一条边,可以看到每一个拐角处的处理规则,拐角处让给新的一条边来继续画,此处都是按照左闭右开的原则。
![](https://i-blog.csdnimg.cn/blog_migrate/f1687f24f60a6a861e548722fd2833ab.png)
C++代码如下:
class Solution
{
public:
vector<vector<int>> generateMatrix(int n)
{
vector<vector<int>> res(n, vector<int>(n, 0)); //使用vector定义一个二维数组,vector<int>(n, 0)指初始化一个vector<int>类型数组,容量为n,初始值为0
int startx = 0, starty = 0; //定义每循环一个圈的起始位置
int loop = n / 2; //每个圈循环几次,例如n为奇数3,那么loop = 1只是循环一圈,矩阵中间的值需要单独处理
int mid = n / 2; //矩阵中间的位置,例如:n为3,中间的位置就是(1,1), n为5,中间的位置就是(2,2)
int count = 1; //用来给矩阵中每一个空格赋值
int offset = 1; //需要控制每一条边遍历的长度,每次循环右边界收缩一位
int i, j;
while(loop--)
{
i = startx;
j = starty;
//下面开始的四个for就是模拟转了一圈
//模拟填充上行从左到右(左闭右开)
for(j = starty; j < n - offset; j++)
{
res[startx][j] = count;
count++;
}
//模拟填充右列从上到下(左闭右开)
for(i = startx; i < n - offset; i++)
{
res[i][j] = count;
count++;
}
//模拟填充下行从右到左(左闭右开)
for(; j > starty; j--)
{
res[i][j] = count;
count++;
}
//模拟填充左列从下到上(左闭右开)
for(; i > startx; i--)
{
res[i][j] = count;
count++;
}
//第二圈开始的时候,起始位置要各自加1,例如:第一圈起始位置是(0,0),第二圈起始位置是(1,1)
startx++;
starty++;
//offset 控制每一圈里每一条边遍历的长度
offset += 1;
}
//如果n为奇数,需要单独给矩阵最中间的位置赋值
if(n % 2)
{
res[mid][mid] = count;
}
return res;
}
};
今日总结:螺旋矩阵不熟,要多练习。长度最小的子数组这题,倒是想到了用双指针法,后续可再回顾。