时间复杂度四个概念
本文创作灵感来源于 极客时间 王争老师的《数据结构与算法之美》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。
是什么
什么是时间复杂度四个概念
- 最好情况时间复杂度:在最理想的情况上,执行这段代码的时间复杂度。
- 最坏情况时间复杂度:在最糟糕的情况上,执行这段代码的时间复杂度。
- 平均情况时间复杂度:用代码在所有情况下执行的次数的加权平均值表示。
- 均摊时间复杂度:在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊结果就等于低级别复杂度。
为什么
为什么要有时间复杂度四个概念
- 算法是我们来解决某一类问题得出应有结果的有限步骤,但是在实际运用中,很有可能在算法进行到某一个点的时候,就已经得到我们最终想要的结果了。所以,在分析出时间复杂度之后,算法有可能在执行之初或者是执行结束,或者是执行的任一时刻就得出结果,停止运行。
- 同一段代码在不同情况下时间复杂度的具体值可能会出现量级差异,为了更全面,更准确的描述代码的时间复杂度,所以引入这4个概念。
- 代码复杂度在不同情况下出现量级差别时就需要区别这四种复杂度,以便更加全面准确的分析时间复杂度。
怎么办
怎么分析代码的这四种时间复杂度
1
2
3
4
5
6
7
8
9
10public int getIndex(int[] list,int val){
int index = 0;
for(int i = 0; i < list.length; i++){
if(val == list[i]){
index = i;
break;
}
}
return index;
}
上述代码中,数组 list ,以及某一个特定的值 val ,getIndex 方法负责找出数组 list 中 val 值得数组下标。
最好情况时间复杂度
- 在 getIndex 方法中,假设 val = 5,我们查找数组 list 中值等于 5 的数组下标。那么,代码运行最少时间的情况就是数组 list 中的第一个元素的值就等于 5 ,则代码 for 循环只执行一次,最好情况时间复杂度为 O(1) 。
最坏情况时间复杂度
- 在 getIndex 方法中,假设 val = 10,我们查找数组 list 中值等于 10 的数组下标。那么,代码运行最少时间的情况就是数组 list 中的最后一个元素的值就等于 10 ,则代码 for 循环执行了 n (n代表数组list的长度) 次,最好情况时间复杂度为 O(n) 。
平均情况时间复杂度
- 平均情况时间复杂度的分析要充分考虑到每一种情况出现的概率,此处分为两个步骤
- 第一步:在 getIndex 方法中,假设 val = 7,我们查找数组 list 中值等于 7 的数组下标。但是,数组中是否有值等于 7 的元素存在两种情况,有或者无,我们就是理论上假设每种情况出现的概率都是 \dfrac{1}{2}
- 第二步:假设数组 list 中存在值等于 7 的元素,那么元素出现在每个位置上的概率就是 1/n (n代表数组list的长度)最终 7 出现在数组中任意位置的概率为 1/2n
- 那么,平均时间复杂度就是每种情况的时间复杂度之和的平均值。每种情况的概率就是 1 1/2n + 2 1/2n + 3 1/2n + 。。。 + n 1/2n = (n+1)/4 去掉多项式的系数和常熟则时间复杂度为 O(n)
均摊时间复杂度
- 从概念上理解,在代码执行过程中,每种情况出现的概率并不是相等的。又或者是大部分情况是每种情况出现的概率是相等的,此时算法时间复杂度为 O(1) ,只有个别情况代码的时间复杂度 O(n) ,此时我们需要将时间复杂度高的耗时操作均分到时间复杂度低的操作中。
- 王争老师讲解中曾提到,均摊时间复杂度是一种特殊的平均情况时间复杂度,一般的均摊时间复杂度就等于最好最好情况时间复杂度。由于这种情况实际运用中很少见,所以我们只需要了解大意,不求甚解即可。我们应该掌握的是这种分析方法:摊还分析法。
总结
初入算法复杂度分析,必是步履蹒跚,一路磕磕绊绊跌跌撞撞。看不懂别慌,也别忙着总结,先读五遍文章先,无他,唯手熟尔~
与诸君共勉