时间复杂度

1. 返回的评测结果

Accepted: 答案正确。恭喜,您通过了这道题。

Wrong Answer: 答案错误。仅仅通过样例数据的测试并不一定是正确答案,一定还有你没想到的地方。

Runtime Error: 运行时错误。像数组越界,指针漂移,无穷递归都可能出现这类问题。

Time Limit Exceeded: 时间超限。请检查程序是否有死循环,或者应该有更快的计算方法。

Memory Limit Exceeded: 内存超限。数据可能需要压缩,或者您数组开太大了,请检查是否有内存泄露。

Output Limit Exceeded: 输出超限。你的输出居然比正确答案长了N倍!

Unknown Error: 评测失败。可能是没有数据,反正不一定是你的锅啦!

时间复杂度_第1张图片

2. 概念

  • 算法分析是指通过数学方法对一个算法的
    时间效率和空间效率经行评估,并判断该
    算法的优劣。
  • 如果算法A的时空复杂度均低于算法B,那
    么我们认为算法A优于算法B。
  • 有时也有以空间换时间或者以时间换空间
    的算法,比如暴搜和记忆化搜索,前者是
    以时间换空间的算法,而后者是以空间换
    时间。

3. 时间复杂度

  • 时间复杂度,从名字就可以知道,它表示
    的是算法运行的时间效率。
  • 一个算法运行所耗费的时间,除了与所用
    的计算软、硬件环境有关外,主要取决于
    算法中指令重复执行的次数,即语句的频
    度相关。
  • 一个算法中所有语句的频度之和构成了该
    算法的运行时间。
for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
    		x++;
  • 这段代码在运行时,每一种语句的频度如下:
  • 频度为N^2: x++, j++, j ≤ N
  • 频度为N: i++, i ≤ N
  • 频度为1: i =1, j =1
  • 算法的总复杂度为O(3N2+ 2N + 2),由于当N特别大时,O(N)和O(N2)相比,时间基本可以忽略。所以对于一个算法而言,我们只保留多项式的最高项,此例中为O(3N2)。通常情况下,为了简化多项式,我们不会保留常数,所以这段代码最终的时间复杂度为O(N^2)。这也就是这个算法的渐进时间复杂度。

3.1. 要记住的标准

  • 既然是为了判断代码运行效率的优劣,各个时间复杂度之间自然就有
    了大小比较关系,通常在N相对比较大的情况下:

O(1) < O(logN) < O(N) < O(N^2) < O(2^N) < … < O(N^N) < …

  1. O(1):表示复杂度为常数。(常数级)
  2. O(N):表示复杂度为N。(线性级)
  3. O(Ni):Ni 表示N的i次幂。(多项式级)
  4. O(sqrt(N)):表示根号N,即N开方。(多项式级)
  5. O(logN):表示以2为底数N的对数。(对数级)
  6. O(i^N):表示i的N次幂。(指数级)
  7. O(N!):表示N的阶乘,即N! = 1 * 2 * 3 * … * N。(阶乘级)

3.2. 扩展

  • 通常情况下递归算法的复杂度为多项式级、指数级或者阶乘级,比如给定排成一列的N个格子,每一个格子可以填1…N的任意一个,求不重复的一共有多少种,那么用递归一位一位的枚举,复杂度就是O(NN);如果规定数字不能重复,复杂度就是O(N!);再规定每一位要么填1,要么填0,复杂度就变成了O(2N)。具体的代码相信你能够写出来,这里就不再写了。
  • 另外还有均摊时间复杂度,以单调队列为例,每一次进如队列和退出队列的变量个数并不一定,最多可能有刚好N个变量。但是从整个算法上来分析,每一个变量一定只进队一次,出队一次。所以总的时间复杂度不是O(N^2)而是O(N)。一般来说,均摊时间复杂度需要有严格的证明,而这个证明多数很麻烦。在临场考试时我们就只能大胆猜测,对拍求证了。

3.3. 考试时的参考

我们知道,考试时1s的运行次数是10^8次,
那么我们就要根据数据规模来判断算法。

  • 如果数据规模在100以内,三重循环就不会超时。
  • 如果数据规模在9000以内,二重循环就不会超时。
  • 如果数据规模在10000以上,你的程序就必须要考虑1重循环了。

4. 空间复杂度

空间复杂度指的是实现算法的空间开销,同样使用多项式来表示。最主要的体现就是数组,数组的大小即为该算法的空间复杂度。

4.1. 计算机基本计量单位

计算机最基本单位为字节 (B),一个int 数据占 4个B。

1024 B=2^10 B =1KB
1024KB=2^20B =1MB
1024 MB=2^30 B =1GB

50M 的内存限制可以定义50*1024*1024 /4 个 int变量 约等于 1000万长度的int数组

4.2. 一般的估算

说到空间复杂度,其实主要担心就是会不会爆内存。这里有一个很简单的方法就可以确定:在C/C++里面有sizeof()这个函数(Pascal里面应该也有),它返回的是变量的字节数,比如说sizeof(int),就会告诉你int所占用的空间大小;sizeof(a),其中a是一个数组,这时返回的就是数组a的总空间大小。对于一个已经写好的程序,我们把它所有静态数组的sizeof()全部加起来,然后除上10^6,得到的数字就是所占用的静态内存MB数,有没有爆内存自然一目了然。

5. 各个算法时间复杂度

5.1 数据结构

时间复杂度_第2张图片

5.2 排序

时间复杂度_第3张图片

5.3 图操作

时间复杂度_第4张图片

5.4 堆操作

时间复杂度_第5张图片

你可能感兴趣的:(时间复杂度)