第二天刷题,在做之前能有一点点思路,但是和答完还是有差距。
977.有序数组的平方
将一个包含正负数的有序数组 的平方进行排序。
思路:
先用一个for循环逐个平方,然后排序。
看完代码随想录之后的思路:
暴力解法:
与我的思路相同,最后排序使用C++内置函数sort。但是时间复杂度较高,为O(n + nlogn)。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int slow=0;
int fast=0;
for(int i=0;i<nums.size();i++)
{
nums[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> result(nums.size(),0);
for(int i=0,j=nums.size()-1;i<=j;)
{
if(nums[i]*nums[i]>nums[j]*nums[j])
{
result[k--]=nums[i]*nums[i];
i++;
}
else
{
result[k--]=nums[j]*nums[j];
j--;
}
}
return result;
}
};
遇到的困难:
for循环中,任何一个语句都可以不写,但是分号一定要有
vector的定义中第一个参数是个数,第二个参数是所有元素用什么填充。
双指针法:for循环的条件语句中,i必须<=j,否则最后一个元素无法写入。
收获:
vector数组是一个能存放任意数据类型(类,结构,普通变量类型等)的动态数组!,在数据结构中就相当于顺序储存的线性表,寻找元素非常快,但是插入元素的时间却很大(list是一个双向链表,在同一个为止插入大量的数据时速度很快,但是查找的速度就会慢很多)
for(初始化语句;判断条件语句;控制条件语句)
{ 循环体语句; }
for循环中的初始化语句和控制条件语句的变量可以不同,只要逻辑不出错可以自行,但是不建议这么写,如果控制条件语句的变量不同,最好放在循环体语句中。
重点:
for循环的条件语句中小于等于必须写上,否则无法将最后一个元素写入新数组中——等于号是否取主要看最后1~2个元素的情况。
209.长度最小的子数组
找出数组中大于等于目标值的最小连续子数组。
思路:
双层循环
看完代码随想录之后的思路:
暴力解法:双循环,外层循环从头到尾找开头,内存循环从当前数值开始,向后依次查找和什么时候大于target。当大于一次,马上终止,进入下一个开头。时间复杂度为O(n^2),空间为O(1)。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result_len=INT32_MAX;
int update_len=0;
int sum;
for(int i=0;i<nums.size();i++)
{
sum=0;
update_len=0;
for(int j=i;j<nums.size();j++)
{
sum+=nums[j];
update_len+=1;
if(sum>=target)
{
//update_len=j-i+1;
result_len=result_len>update_len?update_len:result_len;
break;
}
}
}
return result_len==INT32_MAX?0:result_len;
}
};
滑动窗口法:先找窗口的右界,然后再缩小左界的范围。这样搜索的效率快很多。评价标准是时间复杂度为O(n);直观感受是,在第一次找右界的过程中,已经把前面的序列求和过了一次,尽力减少求左界的次数,避免了暴力解法中每次重复求和的过程。空间复杂度同样为O(1)。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result_len=INT32_MAX;
int update_len=0;
int sum=0;
int i=0;
for(int j=0;j<nums.size();j++)
{
sum+=nums[j];
while(sum>=target)
{
update_len=j-i+1;
result_len=update_len<result_len?update_len:result_len;
sum-=nums[i];
i++;
}
}
return result_len==INT32_MAX?0:result_len;
}
};
遇到的困难:
暴力解法中:
- INT32_MAX是最大值,求最短数组,用最大值和更新值比较,这样就避免了第一次需要用更新值赋值的情况。
- 内层循环中,j-i+1直接可作为子数组长度,不需要每次循环加一来算。
- if+赋值的简要写法:等号后先写条件,问号之后写赋予的值,两种赋值中间用冒号隔开。
滑动窗口解法中:
- 内层while的等于号:相等时,先更新序列长度,再更新和的大小,最后移左界。等号是否取,先看取等时要求的最重要的一步是否执行。不要把下一步混入其中。
- 执行时,先执行要求的任务,最后更新指针的位置。(我把while中的求和写在了更新长度和求result中间)
- 所有变量必须赋初值,不能只定义,不写初值。
收获:
带有随时更新的题,一定先准备两个数字。一个在随时在更新,一个记住当前更新值之中的最值。
循环中,当前的任务和下一次的任务不要放在一起看;不要因为等号就特殊,把等号同样看做是要求的一部分,它具有和不等号一样的效应。
重点:
滑动窗口最重要的是先求右界。
59.螺旋矩阵II
给定一个n,写出一个n^2的螺旋矩阵,从1到n一次填入
思路:
无
看完代码随想录之后的思路:
计算出所需要的圈数,每圈四个循环,将每边的数一次填入。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int startx,starty=0;
int loop=n/2;
int mid=n/2;
int offset=1;
int count=1;
int i,j=0;
while(loop--)
{
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++;
}
startx++;
starty++;
offset+=1;
}
if(n%2==1)
{
res[n/2][n/2]=count;
}
return res;
}
};
遇到的困难:
- 所有设置的变量,一定要注意在写入的过程中,变量发生了什么变化;在下一次的循环中,需要对该变量进行什么操作。第一次写的时候startx、starty都忘记了自增。
- ++放在变量后面,先进行赋值,在进行自增。
- 注意每边循环时的起始条件和限定条件,以及赋初值时的坐标指向。
- 容器初始化:
一维设置数组长度,给定值初始,
N为默认数组长度,全部元素设置为初始值valuevector<int> data(N,value);二维设置数组长度,给定值初始,
N1为行,N2为列,默认值为valuevector<vector<int>> data(N1, vector<int>(N2,value));
收获:
函数的定义:
类型标识符 函数名(形式参数列表)
{
变量声明
语句
}
类型标识符:用来标识函数的返回值类型。这里定义为二维容器。
while的条件,非0即为真,可以用下列第一种方法替换第二种方法:
while(loop--)
{
}
while(loop>=1)
{
loop--;
}
重点:
循环不变量原则:注意每一次循环中确保边界条件统一。(4个边都是左闭右开)
文章讨论了三个编程问题的解题思路,包括有序数组的平方排序,使用双指针和暴力解法,以及滑动窗口解决最小连续子数组问题,最后介绍了构建螺旋矩阵的算法,强调了循环不变量原则和时间复杂度优化。
1094

被折叠的 条评论
为什么被折叠?



