LZ最近在看《Java程序员面试宝典(第三版)》这书,其中在第7章的P81介绍了关于算法的时间复杂度的计算的方法,而这一块我在以前考研的时候也复习过,但是经常不用,所以记忆已经有点模糊了,故而又重新根据这本书来复习了下。首先需要明白时间复杂度的概念。
计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。这是一个关于代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,它考察当输入值大小趋近无穷时的情况。所以一般的算法复杂度有好几种,比如O(n),O(n^2),O(log(2)n),O(nlog(2)n)等等。那么如何计算时间复杂度呢?
下面介绍具体的计算步骤:
⑴ 找出算法中的基本语句;
算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。
⑵ 计算基本语句的执行次数的数量级;
只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。
⑶ 用大Ο记号表示算法的时间性能。
将基本语句执行次数的数量级放入大Ο记号中。
如果算法中包含嵌套的循环,则基本语句通常是最内层的循环体,如果算法中包含并列的循环,则将并列循环的时间复杂度相加。例如:
for (i=1; i<=n; i++)
x++;
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
x++;
第一个for循环的时间复杂度为Ο(n),第二个for循环的时间复杂度为Ο(n^2),则整个算法的时间复杂度为Ο(n+n^2)=Ο(n^2)。
例如:
n = 10;
for(int i = 1; i < n; i++)
for(int j = 1; j < n; j += n/2)
for(int k = 1; k < n ; k = k * 2)
x = x + 1;
考虑这个算法的时间复杂度,首先看最内层,因为K循环从1 == 2^0开始每次变成原来的2倍,故 2 ^ k = n,所以这个次数
k = log(2)n,故而最内层的时间复杂度为 O(log(2)n),然后再看第二层的j,因为每次都是增加n / 2,而这又是一个常数,所以第二层的时间复杂度其实就是O(1),也为常数;再看第一层的i,因为这是一个n的循环,所以时间复杂度为O(n),而因为这三层循环是分别嵌套的,所以应该是三个值相乘,所以最后这个时间复杂度为O(n log(2)n)。
常见的算法时间复杂度由小到大依次为:
Ο(1)<Ο(log(2)n)<Ο(n)<Ο(n log(2)n)<Ο(n^2)<Ο(n^3)<…<Ο(2^n)<Ο(n!)