代码随想录算法训练营第二天|Leetcode 977 有序数组的平方,209 长度最小的数组,59 螺旋数组II
Leetcode 977 有序数组的平方
题目链接 977. 有序数组的平方
文章链接 https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频链接 https://www.bilibili.com/video/BV1QB4y1D7ep
思路
这道一前几天做过,今天做的时候还是想了一会儿,不太应该。双指针很好解决,一个指针指向头部,一个指针指向尾部,指针对应数组下标的数组的值大的一方从结果数组的尾部更新,让两个指针逼近,直到相遇,相遇的点就是结果数组的首项,也就是最小的值
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int length = nums.size();
vector<int> data(length);
int i=0;
int j=length-1;
int k=length-1;
while(i<=j){
if(nums[i]*nums[i]<nums[j]*nums[j]){
data[k--] = nums[j]*nums[j];
j--;
}else{
data[k--] = nums[i]*nums[i];
i++;
}
}
return data;
}
};
本题收获
这次写的时候把大于和等于的情况分开来写了,造成代码很繁琐,把代码合并起来是可以的
当i=j时,是两个指针相遇的时候,所对应的项是结果数组的第一项,要进循环,所以条件是i<=j;
Leetcode 209 长度最小的数组
题目链接 209. 长度最小的子数组
文章链接 https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
视频链接 https://www.bilibili.com/video/BV1tZ4y1q7XE
思路
一开始用暴力做的,求每个数满足条件的长度,并更新最小长度。两个循环,第一个循环用于遍历所有的数,第二个循环将每个数和其下面的几个数相加,直到满足条件并记录长度和更新最小长度,但是暴力的代码在leetcode的第18项测试数据就超时了,原因应该是最坏的情况要遍历到结尾,如果数据过长的话就容易超时,看了卡哥的讲解改用了双指针,有效解决了每次都要遍历到数组尾部的情况。首先定义一个指针end,表示区间截止点,先让end指针移动,满足条件时再更新开始点begin,每次移动记录满足条件的窗口的长度(end-begin+1),并更新最小长度
代码
- 暴力(超时)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int minlen=nums.size(),len=0,sum=0,flag=0;
for(int i=0;i<nums.size();i++){
for(int j=i;j<nums.size();j++){
sum+=nums[j];
len++;
//cout<<len<<endl;
if(sum>=target){
minlen = len<minlen?len:minlen;
cout<<minlen<<endl;
flag = 1;
break;
}
}
sum=0;
len=0;
}
if(flag){
return minlen;
}
return 0;
}
};
- 双指针(滑动窗口)解法
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int begin=0,end,len=0,sum=0;
int minlen=nums.size();
int flag = 0;
for(end=0;end<nums.size();end++){
len++;
sum+=nums[end];
while(sum>=target){
sum-=nums[begin++];
minlen =len<minlen?len:minlen;
len--;
flag = 1;
}
}
if(flag){
return minlen;
}
return 0;
}
};
本题收获
我们可以使用两个指针和分别表示滑动窗口的左右边界,然后通过不断移动右指针来扩大窗口,同时根据问题的要求调整左指针来缩小窗口,并更新一些中间值。当右指针扫描到字符串或数组的末尾时,算法的执行就完成了。
Leetcode 59 螺旋数组II
题目链接 59. 螺旋矩阵 II
文章链接 https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频链接 https://www.bilibili.com/video/BV1SL4y1N7mV/
思路
模拟题,没什么算法,就是一圈一圈的遍历,分两种情况,一种是n为偶数,遍历到最后一圈截至即可,n为奇数,遍历到最后一圈之后还余下一个数。矩阵的题感觉四个顶角点挺重要的,所以我的想法是把四个点的坐标列出来,边界条件就特别清晰了,而且不会写混。
代码
class Solution {
public:
struct point{
int x;
int y;
};
vector<vector<int>> generateMatrix(int n) {
int num = 1;
vector<vector<int>> matrix(n,vector<int>(n,0));
point lt = {0,0};
point rt = {0,n-1};
point rb = {n-1,n-1};
point lb = {n-1,0};
while(1){
if(num==n*n){
matrix[lt.x][lt.y] = num;
break;
}
if(num-1==n*n){
break;
}
for(int i=lt.y;i<rt.y;i++){
matrix[lt.x][i] = num;
num++;
}
for(int i=rt.x;i<rb.x;i++){
matrix[i][rb.y] = num;
num++;
}
for(int i=rb.y;i>lb.y;i--){
matrix[lb.x][i] = num;
num++;
}
for(int i=lb.x;i>lt.x;i--){
matrix[i][lt.y] = num;
num++;
}
lt.x++;
lt.y++;
rt.x++;
rt.y--;
rb.x--;
rb.y--;
lb.x--;
lb.y++;
}
return matrix;
}
};
本题收获
模拟题出遍历矩阵的类似题目,要先考虑四个点的坐标,它们代表了矩阵的所有边界条件(也要根据题目变化来选取相应的边界条件)