1.究竟什么是时间复杂度
时间复杂度是一个函数,它定性描述该算法的运行时间
时间复杂度就是用来方便开发者估算出程序运行的答题时间。
通常会估算算法的操作单元数量来代表程序消耗的时间,这里默认CPU的每个单元运行消耗的时间都是相同的。
假设算法的问题规模为n,那么操作单元数量便用函数f(n)来表示,随着数据规模n的增大,算法执行时间的增长率和f(n)的增长率相同,这称作为算法的渐近时间复杂度,简称时间复杂度,记为 O(f(n))
2.什么是大O
大O用来表示上界的,当用它作为算法的最坏情况运行时间的上界,就是对任意数据输入的运行时间的上界。
拿插入排序来说,插入排序的时间复杂度我们都说是O(n^2) 。
输入数据的形式对程序运算时间是有很大影响的,在数据本来有序的情况下时间复杂度是O(n),但如果数据是逆序的话,插入排序的时间复杂度就是O(n2),也就对于所有输入情况来说,最坏是O(n2)
的时间复杂度,所以称插入排序的时间复杂度为O(n^2)。
3.不同数据规模的差异
大O就是数据量级突破一个点且数据量级非常大的情况下所表现出的时间复杂度,这个数据量也就是常数项系数已经不起决定性作用的数据量。
所以我们说的时间复杂度都是省略常数项系数的,是因为一般情况下都是默认数据规模足够的大,基于这样的事实,给出的算法时间复杂的的一个排行如下所示:
O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(nlogn)线性对数阶 < O(n^2)平方阶 < O(n^3)立方阶
< O(2^n)指数阶
4.复杂表达式的化简
有时候我们去计算时间复杂度的时候发现不是一个简单的O(n) 或者O(n^2), 而是一个复杂的表达式,例如:
O(2n^2 + 10n + 1000)
那这里如何描述这个算法的时间复杂度呢,一种方法就是简化法
去掉运行时间中的加法常数项 (因为常数项并不会因为n的增大而增加计算机的操作次数)。
O(2n^2 + 10n)
去掉常数系数(上文中已经详细讲过为什么可以去掉常数项的原因)。
O(n^2 + n)
只保留保留最高项,去掉数量级小一级的n (因为n^2 的数据规模远大于n),最终简化为:
O(n^2)
如果这一步理解有困难,那也可以做提取n的操作,变成O(n(n+1)) ,省略加法常数项后也就别变成了:
O(n^2)
所以最后我们说:这个算法的算法时间复杂度是O(n^2) 。
也可以用另一种简化的思路,其实当n大于40的时候, 这个复杂度会恒小于O(3 × n^2), O(2 × n^2 + 10 × n +
1000) < O(3 × n2),所以说最后省略掉常数项系数最终时间复杂度也是O(n2)
5.O(log n)中的log是以什么为底?
平时说这个算法的时间复杂度是logn的,那么一定是log 以2为底n的对数么?
可以是以10为底n的对数,也可以是以20为底n的对数,但我们统一说 logn,也就是忽略底数的描述。
假如有两个算法的时间复杂度,分别是log以2为底n的对数和log以10为底n的对数,那么这里如果还记得高中数学的话,应该不难理解以2为底n的对数 = 以2为底10的对数 * 以10为底n的对数。
而以2为底10的对数是一个常数,在上文已经讲述了我们计算时间复杂度是忽略常数项系数的。
抽象一下就是在时间复杂度的计算过程中,log以i为底n的对数等于log 以j为底n的对数,所以忽略了i,直接说是logn。