摘要:
时间复杂度还可分为四种,分别是「最好时间复杂度」、「最坏时间复杂度」、「平均时间复杂度」和「均摊时间复杂度」。
为什么会引入这几种时间复杂度,是由于一段代码会出现多种情况,而在这些不同的执行条件下代码的执行效率会出现变化,所以需要引入这四种时间复杂度,可以更加全面地表达一段代码的执行效率。
最好、最坏时间复杂度
我们先来分析下列代码的时间复杂度。
int findTarget(int[] intArray, int n, int target) {
int index = -1;
for(int i = 0; i < n; i++) {
if(intArray[i] == target) {
index = i;
}
}
return index;
}
这段代码中 n 表示数组的长度,可以分析出时间复杂度是 O ( n ) O(n) O(n),但是这段代码在查找到相应的数据下标后就可以中断循环,所以还可以优化一下。
int findTarget(int[] intArray, int n, int target) {
int index = -1;
for(int i = 0; i < n; i++) {
if(intArray[i] == target) {
index = i;
break;
}
}
return index;
}
此时再来分析时间复杂度就会遇到特殊情况,因为第 6 行代码的 break
使代码有几率可以不遍历完整个数组就结束循环,每次的循环次数就可能出现变化,那这种情况下时间复杂度又需要如何分析?
这段代码的循环会有极端情况和一般情况,先来分析极端情况,当 target
对应的数值出现在数组第一个或者最后一个(包括在数组中找不到对应数值情况),这两种情况的时间复杂度分别为 O ( 1 ) O(1) O(1) 和 O ( n ) O(n) O(n),这两种情况分别对应了最好情况和最坏情况,所以对应的这两种情况下分析得到的时间复杂度就是最好时间复杂度和最坏时间复杂度。
平均时间复杂度
分析完极端情况我们需要分析一般情况,一般情况下,target
对应数组中的数值有 n 种可能(在数组的第 1 位至第 n 位之间的任意一位)或数组中没有与target
对应的数值,所以总共有 n + 1 n+1 n+1 种可能,那每种可能下需要循环的次数分别为 1 , 2 , 3 , . . . . . . , n − 1 , n , n 1, 2, 3, ......, n-1, n, n 1,2,3,......,n−1,n,n 次,一般情况下需要循环的次数也就是 1 + 2 + 3 + . . . . . . + n − 1 + n + n ( n + 1 ) \frac{1 + 2 + 3 + ...... + n -1 + n + n}{(n + 1)} (n+1)1+2+3+......+n−1+n+n,可根据数据公式作出如下推导。
1 + 2 + 3 + . . . . . . + n − 1 + n + n n + 1 = n × ( n + 1 ) 2 + n n + 1 = n × ( n + 1 ) + 2 n 2 × ( n + 1 ) = n 2 + n n + 1 = n 2 + 1 − 1 ( n + 1 ) \frac{1 + 2 + 3 + ...... + n -1 + n + n}{n + 1} = \frac{\frac{n\times(n + 1)}{2} + n}{n + 1}=\frac{n\times(n + 1) + 2n}{2\times(n + 1)}=\frac{n}{2} + \frac{n}{n + 1} = \frac{n}{2} + 1 - \frac{1}{(n + 1)} n+11+2+3+......+n−1+n+n=n+12n×(n+1)+n=2×(n+1)n×(n+1)+2n=