整数非递减数组的有序数组,新数组:每个元素的平方按照非递减排列输出,时间复杂度为O(n)
遍历整个数组,对每一个元素求平方,放到新的数组中;然后再对新的数组中的每一个元素进行排序,但是没有利用题目中有序的概念
时间复杂度是O(n+n^2)
遇到的问题
Q1:设置新数组时出现了疑问,不知道怎么设置一个与原来大小相同的数组
A1w:可以直接定义一个vector变量,这个vector的大小可以动态变化,,可以直接往这个vector中存入数据。
Q2:在排序时出现了困难,忘记怎么排序了,因为要是出现递减的情况时,整段数据都跟着动,且与双指针移除元素相比,这个数据仍然保留,就是交换一下位置,当时想到的是地址这一类复杂的,脑子一团浆糊没想起来。
A2:引入中间变量temp,保存其中一个数据,这样就可以进行数据的传递了呀
class Solution {
public:
vector sortedSquares(vector& nums) {
vector myvector ;
for(int i=0;imyvector[i+1])
{
int temp = myvector[i];
myvector[i] = myvector[i+1];
myvector[i+1] = temp;
}
}
return myvector;
}
};
这种简单的做法,无法比较第一个位置和第二个位置的数据大小,这个问题出在哪呢??
这种做法是一种典型的冒泡排序法,这种做法只排列了一次,不能做到整体的排序
以[1,5,8,7,2,3]这个数组为例
第一次:1-5-8-7-2-3
第二次:1-5-8-7-2-3
第三次:1-5-7-8-2-3
第四次:1-5-7-2-8-3
第五次:1-5-7-2-3-8
这是最终的结果[1,5,7,2,3,8],但是显然这还是一个无序的数组,所以程序中的这种程序是错误的,除了比较相邻元素的大小外,还需要规定每次遍历的次数,这样两层循环嵌套起来,得到最终的比较结果,这也是冒牌排序的精髓所在。
冒泡排序的基本思路是:每次遍历数组,比较相邻的两个元素,如果它们的顺序不正确,则交换这两个元素。通过多次遍历,将最大的元素逐步交换到右侧,从而完成排序;使用双重循环,外层循环控制遍历的次数,内层循环进行相邻元素的比较与交换。在每一轮遍历中,我们将当前遍历到的元素与它后面的元素进行比较,如果它后面的元素更小,则交换它们。
将代码修改如下,即可正常运行,得出正确结果。
class Solution {
public:
vector sortedSquares(vector& nums) {
vector myvector ;
for(int i=0;imyvector[j+1])
{
int temp = myvector[j];
myvector[j] = myvector[j+1];
myvector[j+1] = temp;
}
}
}
return myvector;
}
};
直接对整个数组的每个元素进行求平方操作,然后将平方之后的数据放在原数据对应的位置,从而直接得到新的数组,然后使用sort函数对数组进行递增排序。
时间复杂度是O(n+nlog(n))
补充知识:sort函数默认的排序方式是升序排序,即从小到大,sort(begin,end,cmp);sort函数中参数有三个(第三个可以省略),其中begin是排序数组的起始地址,end是排序数组的结束地址(最后一位要排序元素的地址)这两个参数都是地址。
class Solution {
public:
vector sortedSquares(vector& nums) {
for(int i=0;i
这是一个有序整数数组,是非递减的,例如[-5,-2,0,5,9]这样排列,根据数组的特点可知,数组在第一个位置和最后一个位置的元素的平方最大,中间元素的平方最小,那么此时采用双指针,一个指针指向第一个位置,另一个指针指向最后的位置,比较这两个位置处元素的平方大小,平方大的对应的指针就向前移(向后移),直到二者指针位置相悖。
时间复杂度为O(n)
但是需要注意的是,题目要求的是非递减数组,这个指针指向的是元素的平方的最大值,如果保存元素的话,需将该元素的平方值放置在新数组的最后的位置,这样依次比较放置,从而得出了按照题目要求的非递减数组。
class Solution {
public:
vector sortedSquares(vector& nums) {
vector result(nums.size(),0);
int k = nums.size()-1;
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;
}
};
如果按照这样写的话,为什么会报的错误是这样的
就在刚刚又运行了一遍,又没有错误了,真是神奇啊
改正后的写法是:
class Solution {
public:
vector sortedSquares(vector& nums) {
vector result(nums.size(),0);
int k = nums.size()-1;
for(int i=0,j=nums.size()-1;i<=j;)
{
if(nums[i]*nums[i] < nums[j]*nums[j])
{
result[k--] = nums[j]*nums[j];
j--;
}
else
{
result[k--] = nums[i]*nums[i];
i++;
}
}
return result;
}
};
这两者有什么区别呢??
没有区别,是一样的,都可以运行成功!!!
返回数组中,总和大于等于target的长度最小,且连续的子数组的长度,若无,则返回0.
遍历数组的所有元素,每种加和的情况都计算一遍,最终找到总和大于等于target的最小长度的数组,第一个元素依次加下去,然后第二个元素依次加下去.......这样最终将所有元素之间可能的情况都加一遍,分别比较这些和与target的大小,筛选出和大于等于tartget的元素组合,最后再比较这些筛选出的元素组合的长度,找到长度最小的那一个。
以[2,5,7,3]为例,target=10
2+5=7小于target排除
2+5+7=14保留 ,长度为3
2+5+7+3=17保留,长度为4
5+7=12保留,长度为2
5+7+3=15保留,长度为3
7+3=10保留,长度为2 (因此数组中长度最小的且元素总和大于等于target的数组长度是2)
难点,程序不会编写,可能是自己的逻辑比较混乱吧
使用两个for循环,不断寻找符合条件的子序列,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。(超时)
class Solution {
public:
int minSubArrayLen(int target, vector& nums) {
int result = nums.size();
int sum = 0;
int sublength = 0;
for(int i = 0;i= target) //正整数数组求连续子数组,所以一旦出现大于target的组合,就是最短的,后面的相加不考虑
{
sublength = j - i + 1;
result = result < sublength ? result : sublength;
break;
}
}
}
result = result == nums.size() ? 0 : result; //判断result是否有赋值
return result;
}
};
滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果,使用1个for循环完成暴力解法中两个for循环的操作。
只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。
在本题中实现滑动窗口,主要确定如下三点:
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
解题的关键在于 窗口的起始位置如何移动
class Solution {
public:
int minSubArrayLen(int target, vector& nums) {
int i = 0;
int sum = 0;
int result = nums.size();
int sublength = 0;
for(int j = 0;j= target)//这里注意一定要是while,因为尾指针不动,控制首指针,首指针没动一次,都要进行判断
{
sublength = j - i + 1;//定义满足条件的数组的长度
result = result < sublength ? result :sublength;
sum = sum - nums[i];
i++; //移动首指针
}
}
return result = result == nums.size() ? 0 : result;//这种返回方式在整个数组长度都没能达标的情况下,返回0,而不是数组的长度
// return result; 如果直接return result的话,可能出现遍历所有的元素都没能大于target的情况,最终返回整个数组的长度
}
};
这个窗口法书写代码的时候注意
(1)那个判断条件是while循环,而不是if,因为是在外面的for循环基础上,这个尾指针不动,首指针移动,所以还要继续判断其和与target的大小;
(2)然后就是最后return result时,一定要判断result与nums.size()的大小,因为会有这样的情况出现,nums=[1,1,1],target=5,这时即便遍历了所有情况的和,依然没有找到题目要求的子数组,,如果直接return result,最后会返回整个数组的长度,因为遍历了所有元素,都没能达到最终的结果,返回的就是一个最终for循环之后得到的一个值。
根据正整数n,将1~n^2按照螺旋顺序排成正方形
坚持循环不变量原则。
模拟顺时针画矩阵的过程:
由外向内一圈一圈这么画下去。
要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画,坚持了每条边左闭右开的原则.
这种方法需要定义二维数组,vector
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
while(n/2)
{
for(int j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
if(n%2==1)
{
num[i][j] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它
单独拎出来分析,因为在它前面的那个正方形最后一次得到的i,j值
对应的位置就是指向了这个中间的位置,即最后一个数的位置,所
以对这个位置直接赋值即可
}
}
return num;
}
};
这个代码会报如下的错误,错误的原因是下面的那个if判断放到了循环的里面,导致整个过程执行出错。
if(n%2==1)
{
num[i][j] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它
单独拎出来分析,因为在它前面的那个正方形最后一次得到的i,j值
对应的位置就是指向了这个中间的位置,即最后一个数的位置,所
以对这个位置直接赋值即可
}
所以将代码修改如下:
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
while(n/2)
{
for(int j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[i][j] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
但是又会出现这样的错误:说j未定义,
改正如下:将i,j在前面定义,
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
while(n/2)
{
for(int j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[i][j] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
但是还是会报错,因为前面定义了i,j的类型int,同样后面在for循环中初始化i,j时,也定义了i,j的类型为int,在前面定义了i,j的类型就可,后面不要再定义了
代码修改如下:
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
while(n/2)
{
for(j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[i][j] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
此时又会报错,真的是错误一个接一个来,头都大了!!!显示超出时间限制,我真的会谢!!要吐血了。
所以实在没有办法了,照着卡哥代码一行一行对,进行一步一步修改。
初步修改了对于n为奇数的最终值 num[mid][mid] = count;
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
int mid = n/2;
while(n/2)
{
for(j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[mid][mid] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
还是会报超时错误
继续修改
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
int mid = n/2;
int loop = n/2;
while(loop)
{
for(j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[i][j] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
将括号中的n/2改为loop=n/2 loop-- (个人感觉和这个没有关系)
不幸的是还是会报错!!!!Oh no
不过这次不是报超时错误了,而是报了新的错误,是该哭呢还是该笑呢!!吧奖励自己一个表情
由此可以联想到在此基础上对num[i][j]=count的修改会出现怎样的错误,本着负负为正的思想,我想着这两个既然都有错误,万一加在一起,错误抵消了呢?结果,哈哈哈哈哈,果不其然,还是报错,报和上面相同的错误。
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
int mid = n/2;
int loop = n/2;
while(loop--)
{
for(j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[i][j] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
既然这样,我就拿出我的杀手锏,一行一行对,总行了吧,这样应该没错了吧
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
int mid = n/2;
int loop = n/2;
while(loop--)
{
i=startx;
j=starty;
for(j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[mid][mid] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
我通过一行一行对照,发现卡哥的代码在循环中加入了i和j的初始化,都给他们赋了值,可能我的基础知识还不够扎实,所以我认为,这两个for循环中已经初始化了赋了值后面的就不用再赋值了吧,但是这样不行,会报上述错误,所以还是将它们赋了值,哎,写到这里突然开窍了,因为这是个二维数组啊,当然要给二维数组的i,j赋初始值啊,不然的话,数组是在什么基础上(哪一行,哪一列)进行操作啊,自己真的是2啊!
果不其然,还真跑出结果来了,虽然结果有错误,
自己又仔细对照检查了一遍代码,发现是第2个for循环的i,j填错了,最后将代码改正,得到了正确的结果,这道题写的真是太不容易了,主要是自己不够认真,没有下次了。
class Solution {
public:
vector> generateMatrix(int n) {
vector> num(n, vector(n,0)); //定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0。
int startx=0;
int starty=0;
int offset=1;
int count=1;
int i,j;
int mid = n/2;
int loop = n/2;
while(loop--)
{
i=startx;
j=starty;
for(j=starty;jstarty;j--)
{
num[i][j] = count++;
}//最后一行,列会发生变化,所以是j进行操作,这行代码运行完成后,对于第一圈,j变成了0,即num指向了最后一行的第一个元素
for(;i>startx;i--)
{
num[i][j] = count++;
}//第一列,行会发生变化,所以是i进行操作,这行代码运行完成后,对于第一圈,i变成了0.即num指向了第一列的第一个元素
startx++;
starty++;
offset++;
}
if(n%2==1)
{
num[mid][mid] = count;//对于n为奇数的情况,最后一个元素不构成正方形的一条边,把它单独拎出来分析,因为在它前面的那个
//正方形最后一次得到的i,j值对应的位置就是指向了这个中间的位置,即最后一个数的位置,所以对这
//个位置直接赋值即可
}
return num;
}
};
今天利用双指针的思想进行有序数组的排列和螺旋矩阵的书写,遇到了一些错误,同时自己也通过查资料,问群友也一个个解决了,收获了很多,觉得自己还有很多不足,自己不够认真,犯了很多低级错误,下次不可以再犯了。