C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ

题目1:977  有序数组的平方

题目链接:有序数组的平方

对题目的理解

整数非递减数组的有序数组,新数组:每个元素的平方按照非递减排列输出,时间复杂度为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;
    }
};

这两者有什么区别呢??

没有区别,是一样的,都可以运行成功!!!


题目2:209  长度最小的子数组

题目链接:长度最小的子数组

对题目的理解

返回数组中,总和大于等于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循环 完成了一个不断搜索区间的过程。(超时)

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)
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循环里的索引。

解题的关键在于 窗口的起始位置如何移动

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
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循环之后得到的一个值。


题目3:59  螺旋矩阵Ⅱ

题目链接:螺旋矩阵Ⅱ

对题目的理解

根据正整数n,将1~n^2按照螺旋顺序排成正方形

自己没有啥思路,直接看的视频

坚持循环不变量原则。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去

要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第1张图片

每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画,坚持了每条边左闭右开的原则.

  • 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
  • 空间复杂度 O(1)

这种方法需要定义二维数组,vector> num(n, vector(n,0)),定义了一个二维的vector对象num,包含n行和n列,初始化为每个元素都是0

解法

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判断放到了循环的里面,导致整个过程执行出错。

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第2张图片

 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未定义,

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第3张图片

改正如下:将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的类型就可,后面不要再定义了

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第4张图片

代码修改如下:

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;
    }
};

此时又会报错,真的是错误一个接一个来,头都大了!!!显示超出时间限制,我真的会谢!!要吐血了。

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第5张图片

所以实在没有办法了,照着卡哥代码一行一行对,进行一步一步修改。

初步修改了对于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

不过这次不是报超时错误了,而是报了新的错误,是该哭呢还是该笑呢!!吧奖励自己一个表情

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第6张图片

由此可以联想到在此基础上对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;
    }
};

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第7张图片

既然这样,我就拿出我的杀手锏,一行一行对,总行了吧,这样应该没错了吧

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啊!

果不其然,还真跑出结果来了,虽然结果有错误,

C++ day2 数组 977有序数组的平方,59螺旋矩阵Ⅱ_第8张图片

自己又仔细对照检查了一遍代码,发现是第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;
    }
};

总结

今天利用双指针的思想进行有序数组的排列和螺旋矩阵的书写,遇到了一些错误,同时自己也通过查资料,问群友也一个个解决了,收获了很多,觉得自己还有很多不足,自己不够认真,犯了很多低级错误,下次不可以再犯了。

你可能感兴趣的:(c++,算法,数据结构)