在计算机科学中,算法的时间复杂度是衡量算法效率的重要指标。时间复杂度描述了算法在输入规模增加时,执行时间如何增长。本文将通过一些常见的算法示例,介绍如何进行时间复杂度分析。
常见的时间复杂度
以下是一些常见的时间复杂度及其含义:
- O(1) : 常数时间复杂度,算法的执行时间不随输入规模的变化而变化。
- O(log n) : 对数时间复杂度,算法的执行时间随输入规模的对数增长。
- O(√n) : 平方根时间复杂度,算法的执行时间随输入规模的平方根增长。
- O(n) : 线性时间复杂度,算法的执行时间与输入规模成正比。
- O(n log n) : 线性对数时间复杂度,常见于一些高效的排序算法。
- O(n^2) : 二次时间复杂度,常见于简单的嵌套循环。
- O(n^3) : 三次时间复杂度,常见于三重嵌套循环。
- O(2^n) : 指数时间复杂度,常见于一些递归算法。
示例分析
让我们从两个简单的例子开始
def algo_constant(n):
"""Time: O(1)"""
print(f"do something for {n}")
def algo_linear_0(n):
"""Time: O(n)"""
for i in range(n):
print(f"do something for {i}")
这两个示例中,一个是O(1), 一个是O(n),相信你凭直觉就能找到答案,不需要任何过度分析
再看一个没那么无聊的例子,如果迭代的步长不是1呢
def algo_linear_2(n):
"""Time: O(n)"""
for i in range(0, n, 2):
print(f"do something for {i}")
凭直觉能看出这个函数迭代的次数为n/2, O(n/2) = O(n),因为两者没有量级的差异,当n极大的时候,因子1/2可以忽略不计,同理当步长为3,4,5...时,算法的时间复杂度都是O(n)我们可以得出结论,线性迭代的步长不影响时间复杂度。
更一般的分析方法
O(n)的算法都比较容易看出来,再来看一个不是O(n)的例子
def alog_logrithemic(n):
"""Time: O(log(n))"""
i = 1
while i < n:
print(f"do something for {i}")
i *= 2
这个函数时间复杂度为 O(log n)。如何得出这个结论呢?让我们来一步步分析
- 定义问题:设迭代次数为
k, 时间复杂度可以简化为找出迭代次数k和n的关系 - 停止条件:
k的大小取决于循环停止条件,在这个例子中是i >= n,可以简化为i = n。 - 找到迭代变量与
k的关系:迭代变量是i,每次迭代中,i的值都会变为之前的2倍,即i = 1, 2, 4, 8, ..., 可以发现i = 2^k。 - 求解k:
i = 2^k代入停止条件,得到2^k = n, 因此k = log2(n)。 - 得出结论:循环的迭代次数
k是log2(n)的数量级。这意味着算法的时间复杂度是O(log(n))。
以上的分析思路基本就是分析迭代时间复杂度的方法了,让我们用这个方法试试分析另一个例子
def algo_root(n):
"""Time: O(sqrt(n))"""
i = 1
while i * i < n:
print(f"do something for {i}")
i += 1
该函数的时间复杂度为 O(√n)。分析如下
- 定义问题:设迭代次数为
k, 时间复杂度可以简化为找出迭代次数k和n的关系 - 停止条件:
k的大小取决于循环停止条件,在这个例子中是i*i >= n,可以简化为i*i = n。 - 找到迭代变量与
k的关系:迭代变量是i,每次迭代中,i = 1, 2, 3, 4, ..., 可以发现i = k。 - 求解
k:i=k代入停止条件,得到k*k = n, 因此k = √n。 - 得出结论:循环的迭代次数
k是√n的数量级。这意味着算法的时间复杂度是O(√n)。
嵌套循环
如果两个循环嵌套会怎样呢?例如这个例子
def algo_nlogn(n):
"""Time: O(n log(n))"""
for i in range(n):
j = 1
while j < n:
print(f"do something for {i} and {j}")
j *= 2
在这个函数中,外层循环执行 n 次,内层循环执行 log(n) 次,因此总的时间复杂度为 O(n log n)。
总结
K分析法
K分析法是一种系统化的方法,用于分析算法的时间复杂度。其核心思想是通过定义迭代次数 k 来找出算法的时间复杂度。具体步骤如下:
- 定义问题:设迭代次数为
k,时间复杂度可以简化为找出迭代次数k和输入规模n的关系。 - 停止条件:确定循环的停止条件,例如某个变量达到特定值。
- 找到迭代变量与
k的关系:分析每次迭代中变量的变化情况。 - 求解
k:将迭代变量的关系代入停止条件,用代数方法求解k。 - 得出结论:根据
k的数量级,得出算法的时间复杂度。
通过这几个步骤,我们可以系统地分析出各种复杂度的算法,如 O(log n)、O(√n) 等。
嵌套循环乘法规则
嵌套循环乘法规则用于分析含有嵌套循环的算法的时间复杂度。其基本思想是将每层循环的时间复杂度相乘。假设有两个嵌套循环,外层循环的时间复杂度为 O(f(n)),内层循环的时间复杂度为 O(g(n)),那么整个算法的时间复杂度为 O(f(n)g(n))。
通过理解和应用K分析法和嵌套循环乘法规则,我们可以快速分析出多层嵌套循环的时间复杂度。