前言
本科时,复杂度一直是卡在心里的坎,看课本上定义也没看懂,老师也没讲得很清楚、、......把人搞得稀里糊涂,最后考试全靠背,对这方面知识一直是模模糊糊的。最近刷力扣时又重新开始接触复杂度,所以下定决心把这些知识搞清楚,同时也希望本文能够帮助到你。本文会对时间复杂度进行介绍,帮助你重新认识算法的时间复杂度。
一、时间复杂度是什么?
这里就不放出时间复杂度的定义了,简单地说:时间复杂度是用来衡量算法的计算运行效率一个维度,算法中每进行一次计算的运行时间可以看作是相等的,所以可以通过计算代码的运行次数来间接表示代码的运行时间和效率,通常用大O表示法来表示。
需要注意的是,同一个算法在不同性能机器上的运行时间不一定相同,甚至在同一台机器上多次运行的时间也不一定相同。所以需要时间复杂度来解决这一问题,其公式为,其中表示代码执行次数的和,表示正比例关系,一些常见的如下图所示。
通常情况下,我们默认数据的规模足够大,所以会忽略各种常数项的系数(在数据量足够大的情况下,常数项系数的影响可以被忽略)。对于常见的时间复杂度有如下的排序:
接下来的一部分将通过介绍常见的一些时间复杂度表示,以此由浅入深地对时间复杂度有进一步的认识。
二、常见的时间复杂度及复杂表达式化简推导
1.
以下面代码为例,在算法中不涉及循环递归等结构,无论算法程序的输入n为多少,算法始终只会运行一次,那么该算法的时间复杂度就是。
let i = 0;
if(i != 1) {
return false;
}else {
return true;
}
2.
代码如下所示,循环内的计算每进行一次,距离跳出循环就越近,该算法需要次运算结束。当n的数量级足够大的时候,该例子的循环内的常数值大小对算法的实际运行次数影响就不大了。所以化简后可以将类似的算法的复杂度视为,此时表达式中的log就忽略了底数。
let res = 1;
while(res < n) {
res *= 2;
}
3.
复杂度为 的算法比较容易理解,随着输入数据n的增大,算法的计算次数也会随之线性增长。比较典型的就是for循环。
let sum = 0;
for(let i = 0; i < n; i++) {
sum += 1;
}
4.
将时间复杂度为的算法执行n遍后得到的算法的时间复杂度就是。代码举例如下:
for(let i = 0; i < n; i++){
let res = 1;
while(res < n) {
res *= 2;
}
}
5.
同样的,把时间复杂度为的算法执行n遍后得到的算法的时间复杂度就是。类似的,、也是一样,依此类推。
let res = 0;
for(let i = 0; i < n; i++){
for(let j = 0; j < n; j++){
res += 1;
}
}
6. 复杂表达式的化简
在计算时间复杂度时,除了我们之前介绍的这些比较常见的一些简单的时间复杂度类型外,还有可能出现较为复杂的表达式,那么我们就可以通过化简的方式将其转化为常见的类型。
例如:
初始时间复杂度为:
首先可以去除末尾的常数项以及先前各项的常数系数,正如之前所介绍的,当n足够大时,这些常数带来的影响就变得非常小了,从而得到复杂度;
接下来可以把n这一项给除去,在n非常大时,n^3的数据规模要远大于n,所以得到的简化后的时间复杂度可以表示为。
总结
本文对时间复杂度进行了相关的介绍,在实际使用时并不需要严格按照时间复杂度的高低来选择使用的算法,因为我们目前所讨论的算法时间复杂度都是在最坏情况下,也就是n的数量级非常大的情况。对于一些数据规模较小的运算,可以根据实际情况采取不同的算法。
欢迎关注公众号【Jose的写字台】,同样欢迎各位一起讨论、批评与指正,共同进步!