一、#867转置矩阵 #数组
时间复杂度为O(mn),空间复杂度为O(1),除了返回值以外,额外使用的空间为常数。
1、有一种情况没有试,这种其实通不过,举例子时应注意举的两个特例的区别,这个要考虑在内
没有考虑转置矩阵的存储问题,其实跟原矩阵已经不一样,区别是行列数的大小不同,需要新建矩阵,不然就会报内存错,堆缓冲区溢出
因为若使用原数组,边界会越界。
2、大体改完的小毛病,注意二维数组元素的书写;定义m,n若都是同一数据类型,可以只写一个int。
3、注意,
vector二维数组已知行数和列数的定义,因为vector容器表示的是一维数组,所以vector<vector>这种形式的数组是二维数组,<>里面是数组的类型;
如何得到vector二维数组的行数和列数;
函数头的参数传送的是地址,局部函数的matrix的值变了,那么原来调用它的函数的值也会改。
4、堆缓冲区的相关知识点(未细看)关于堆栈的讲解(我见过的最经典的)_忆水思寒的博客-CSDN博客_堆栈
堆heap是程序员自己申请,指明大小,由程序员分配释放,用到malloc和free;栈stack是由系统自动分配释放,存放函数参数的值,局部变量的值
二、面试题17.10 主要元素 #数组#分治算法
时间复杂度o(nlogn),空间复杂度o(logn),因为上面先有排序,为快排是o(nlogn),后面的遍历为o(n),而nlogn高于线性n;注意:快速排序是有空间复杂度的
1、一点没想起来思路,先排序;
2、关键词是超过一半的元素一样,所以遍历时遍历为一半加1的次数就行,多了不用;
3、因为排序了,只需要判断这些次数的头和尾元素相同就达标了;可能实际的主要元素的数量比一半加1多,但也不用管
4、我自己参考最高赞后的改进,把for循环遍历的范围从[i+num.size()/2,num.size())变为[0,nums.size()/2+1)了,这样提交后执行时间从20s变为16s,更快,可能前边因为加了一个i的原因?;内存这个不稳定,有时高有时低
5、sort排序参数为数组的起始地址和结束地址,不是数字下标,前提是这个数组是一个vector来表示
6、这样设定遍历次数为一半加1后,找不到相等的就返回-1,比如1233,这种3并没有超过一半
第二种方法:摩尔投票法:
时间复杂度o(n),空间复杂度o(1),这个摩尔投票法要比排序法的时间复杂度要好。
1、一般most要在循环内去开始赋值,for循环一般都是从0开始,不要自己给安排从1,不要循环外赋值,这样一个循环解决所有问题,单独拿出一个在循环外其他的再另外看不容易看出规律,规律要有普适性;
2、cnt初始化为0,为1才算值存在,为1才会代表值,为0什么不代表;
3、要弄清楚先分为两大步来的,一是通过循环判断先把能够解决最后cnt为0的情况,仅仅通过第一步能够解决类似123451,1212,1223,32,不用第二步就能返回得到-1,这里面排除的也包括有最多数的,即众数,也有没有最多数的,即不存在众数的,但数目都没超过一半的情况,这种结果cnt都为0。
所以第二步,需要再for循环对最后cnt>0时的most数计数,看是否超过一半。通过第2步,能解决类似1233,123,121,122,12121,12221,125959555,2211122,能排除另一部分cnt>0时数没有超过一半的情况,这里面包括有最多数的,也包括没有最多数的情况。
不能想着一次性就把两个问题同时解决。
4、注意不要被众数误导,这两步骤都会有最多数存在的可能。分步骤的标准不是众数或者是众数,而是cnt==0,或者cnt>0。也就是说这两步其实是在逐步排除可疑的数,第一步就是先用cnt=0前后两个不同的数抵消,大体排除一部分,得到的仍是可疑数,第二步再通过超过一半来精细确定,最后把另一部分再排除。
三、#977 有序数组的平方 #数组#双指针
第一种排序法:
第一种排序法,时间复杂度为o(nlogn),空间复杂度o(logn),除了存储答案的数组以外,我们需要 O(logn) 的栈空间进行排序。
快速排序的空间复杂度?
总结:通常涉及到能够用快速排序算法解决的问题,而快排是所有排序算法中最好的,通常从时间复杂度上不是最好的方法,因为时间复杂度为o(nlogn),要找o(n)的最好,且空间复杂度也不是最好为o(logn),通常会找有没有o(1)的。
我的改成了它,又另外新建了一个数组,这样比较科学,因为用原来的如果是空间变了还会边界溢出,但这样时间变多,内存变多。如果不变,可以用我的法,比较省,不会结果时间和内存都变不好了。
但第一种方法没有用到有序数组的条件,简化复杂度
我自己写的第二种方法,双指针法,执行后结果不好,变得更慢了,只打败了5%这种,原因使用了insert函数。其他的像一些定义一个变量,小函数算大小的调用,算绝对值的调用,一些小运算都没太事。
而参考的下面这个会正常一些,这个与第一种方法新建数组的那一种比较,确实会时间更短了,内存更小了。
时间复杂度o(n),空间复杂度o(1)
1、注意不要使用insert函数,里面还会包括一个begin函数,只要使用这个insert,内存变大,运行时间变长很多。
2、如果用insert函数,只需声明数组,不需要定义数组,不需要设置数组的大小以及初始化,哪怕只设置数组的大小也不行,不然这两个的结果一样都是,后面会有数组大小个0。
所以,用insert只需要声明数组即可。
3、所以把insert用其他方法代替,先定义好数组分配好内存初始化,然后直接用res[k--]赋值即可。
4、因为其他的点并不会太影响,所以怎样写都可以,可以用变量表示size再继续亦可以不,或者平方可以直接相乘也可以用函数pow
5、新建的数组命名和原来数组名不要太相似
6、小问题,++i会更好一点,因为i++多了一个副本,具体详见(C++)i++和++i,哪个效率高一些_suixinsuiyuan33的博客-CSDN博客
注意:
这样