今天刷leetcode的时候有了一个关于时间复杂度的疑问。
leetcode215题是找第K大的数。
里面题解的partition方法的时间复杂度是O(n),怎么得出来的呢?
按照我的理解,时间复杂度就是程序运行次数的数量级。
第1次遍历了整个array,代码运行次数也就是n,
第2次遍历了1/2个array,代码运行次数是n/2,
第3次遍历了1/4个array,代码运行次数是n/4,
同理一直叠加,得到总执行次数为
n + n/2 + n/4 + n/8 +...+...
然而,
1/2 + 1/4 + 1/8 + 1/16 +...+... 趋近于 1
所以,
n + n/2 + n/4 + n/8 +...+...趋近于2n
省略掉常数之后,
就是O(n)
然而,二分查找好像跟这个也差不多,也是每次取一半来计算,那为什么时间复杂度却是O(logn)?
因为,二分查找中的数组是排好序的。
找到中间值的时间复杂度为O(1),而不用去遍历数组。
所以执行一次代码就能找到中间值。
执行一次代码后,剩下n/2个数,
执行两次代码后,剩下n/4个数,
执行三次代码后,剩下n/8个数,
...
执行k次代码后,剩下n/(2^k)个数。
在最坏的情况下,执行k次代码后,只剩下1个数。
这个数就是我们要找的数。
那么,在最坏的情况下,
n/(2^k) = 1
推出,
n = 2^k
可得,
k = log2(n)
省略掉常数之后即为,O(logn)
最后,由于这个跟快速排序强相关,下面顺便用这种思路来推导下,为什么快速排序的时间复杂度为O(nlogn)呢?
在快速排序中,
遍历1次数组后,代码的运行次数也就是n,能够使得1个数字在正确的位置上。
遍历2次数组后,代码的运行次数也就是2n,能够使得3个数字在正确的位置上。
遍历3次数组后,代码的运行次数也就是3n,能够使得7个数字在正确的位置上。
...
遍历k次数组后,代码的运行次数也就是kn,能够使得(2^k)-1个数字在正确的位置上。
我们的终极目的是,使得n个数字在正确的位置上,即为完成了排序。
那么,
(2^k)-1 = n
可推出,
2^k = n + 1
即,
k = log2(n+1)
由于代码的运行次数为kn,
所以可以得到,
kn = n * log2(n+1)
省略常数之后即为,O(nlogn)
author:xjnull
email:xjnull@gmail.com