我们知道当一个算法的循环次数每次减少一半时,时间复杂度通常会变成 是 O ( l o g n ) {O(logn)} O(logn) ,我们可以用二分查找算法作为示例来推算这个时间复杂度的计算过程。
问题背景
假设我们有一个有序数组,我们要在这个数组中查找一个特定的元素。如果元素存在,我们返回其索引;否则返回 -1。
算法步骤
- 比较目标值与数组的 中间元素。
- 如果目标值等于中间元素,返回其索引。
- 如果目标值小于中间元素,则在左半部分继续查找。
- 如果目标值大于中间元素,则在右半部分继续查找。
- 重复上述步骤,直到找到目标值或者子数组为空。
每次查找时,数组的大小减少一半。
时间复杂度分析
- 第一次查找时,数组的大小是 n {n} n。
- 第二次查找时,数组的大小是 n / 2 {n/2} n/2。
- 第三次查找时,数组的大小是 n / 4 {n/4} n/4。
这样下去,每次查找数组的大小都会减半。
假设我们进行了 K {K} K 次查找后,数组的长度 length 变为 1。
因此我们可以得到下列等式
n × ( 1 2 ) k = 1 n\times\left(\frac12\right)^k=1 n×(21)k=1
解这个方程:
n × ( 1 2 ) k = 1 n\times\left(\frac12\right)^k=1 n×(21)k=1
两边同时 除以 n 得:
( 1 2 ) k = 1 n \left(\frac12\right)^k=\frac1n (21)k=n1
然后,对两边取对数(以2为底):
log 2 ( ( 1 2 ) k ) = log 2 ( 1 n ) \log_2 \left( \left( \frac{1}{2} \right)^k \right) = \log_2 \left( \frac{1}{n} \right) log2((21)k)=log2(n1)
根据对数的幂法则 log b ( a c ) = c log b ( a ) {\log_b(a^c) = c \log_b(a)} logb(ac)=clogb(a) 我们有下面变式:
k log 2 ( 1 2 ) = log 2 ( 1 n ) k \log_2 \left( \frac{1}{2} \right) = \log_2 \left( \frac{1}{n} \right) klog2(21)=log2(n1)
因为 log 2 ( 1 2 ) = − 1 {\log_2 \left( \frac{1}{2} \right) = -1} log2(21)=−1 所以:
k × ( − 1 ) = log 2 ( 1 n ) k \times (-1) = \log_2 \left( \frac{1}{n} \right) k×(−1)=log2(n1)
由于 log 2 ( 1 n ) = − log 2 ( n ) {\log_2 \left( \frac{1}{n} \right) = -\log_2(n)} log2(n1)=−log2(n), 所以:
− k = − log 2 ( n ) -k = -\log_2(n) −k=−log2(n)
k = log 2 ( n ) k = \log_2(n) k=log2(n)
因此,二分查找算法在最坏情况下需要 log 2 ( n ) {\log_2(n)} log2(n)次迭代,这就是其时间复杂度为 O ( log n ) {O(\log n)} O(logn) 的原因