时间复杂度的讲解及总结
你好,我是悦创。
时间复杂度是衡量一个算法执行效率的重要指标,它表示随着输入数据规模的增加,算法执行时间增长的速度。时间复杂度通常以大 O 记法表示,关注最坏情况的时间增长趋势。
以下是常见的时间复杂度类型及其对应的 Python 代码示例,涵盖了常见的操作和算法,帮助你更好地理解每种时间复杂度。
1. 时间复杂度的讲解
1.1 O(1) - 常数时间复杂度
常数时间复杂度意味着无论输入数据的规模多大,算法的执行时间都不会改变。
示例:
def constant_time_example(arr):
return arr[0] # 只访问了第一个元素,时间复杂度是 O(1)
# 示例
arr = [1, 2, 3, 4]
print(constant_time_example(arr))时间复杂度分析:该算法访问数组的第一个元素,操作次数不随数组大小变化,因此时间复杂度为 O(1)。
1.2 O(n) - 线性时间复杂度
线性时间复杂度意味着算法的执行时间随着输入数据规模的增加而线性增长。
示例:
def linear_time_example(arr):
total = 0
for num in arr: # 遍历数组每个元素
total += num
return total
# 示例
arr = [1, 2, 3, 4, 5]
print(linear_time_example(arr))时间复杂度分析:算法需要遍历数组的每个元素,因此执行次数与数组的大小 n 成正比,时间复杂度为 O(n)。
1.3 - 平方时间复杂度
平方时间复杂度通常出现在嵌套循环中,意味着算法的执行时间随着数据规模的增加呈平方增长。
示例:
def quadratic_time_example(arr):
for i in range(len(arr)):
for j in range(len(arr)):
print(arr[i], arr[j]) # 双重循环
# 示例
arr = [1, 2, 3]
quadratic_time_example(arr)时间复杂度分析:该算法包含两个嵌套的循环,每个循环都执行 n 次,因此时间复杂度为 。
1.4 O(log n) - 对数时间复杂度
对数时间复杂度通常出现在递归算法中,例如二分查找。它表示算法的执行时间随数据规模的增加呈对数增长。
示例:
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
# 示例
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
target = 5
print(binary_search(arr, target))时间复杂度分析:每次查找都将问题规模减半,因此时间复杂度为 O(log n)。
1.5 O(n log n) - 线性对数时间复杂度
常见的 O(n log n) 时间复杂度出现在高效的排序算法中,例如归并排序、快速排序等。
示例(快速排序):
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
# 示例
arr = [3, 6, 8, 10, 1, 2, 1]
print(quick_sort(arr))时间复杂度分析:快速排序的时间复杂度是 O(n log n),因为每次分割数组为两部分,然后对每部分递归排序,分割的过程是 O(log n),每次分割需要处理 n 个元素。
1.6 - 指数时间复杂度
指数时间复杂度通常出现在递归算法中,意味着算法的执行时间随着输入数据规模的增加呈指数增长。
示例(斐波那契数列):
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 示例
print(fibonacci(6))时间复杂度分析:斐波那契数列的递归算法的时间复杂度为 ,因为每个递归调用会生成两个子问题,递归树的大小以指数方式增长。
1.7 - 阶乘时间复杂度
阶乘时间复杂度常出现在排列组合相关问题中,如暴力破解的排列问题。
示例(全排列):
import itertools
def generate_permutations(arr):
return list(itertools.permutations(arr))
# 示例
arr = [1, 2, 3]
print(generate_permutations(arr))时间复杂度分析:全排列的数量是 n!,即输入数据的所有可能排列组合,因此时间复杂度为 O(n!)。
1.8 总结
| 时间复杂度类型 | 示例 | 时间复杂度分析 |
|---|---|---|
| O(1) | 访问列表的一个元素 | 执行时间不随数据规模变化 |
| O(n) | 遍历列表 | 每个元素访问一次,执行次数与数据规模成正比 |
| O(n^2) | 双重循环遍历列表 | 嵌套循环,执行次数为数据规模的平方 |
| O(log n) | 二分查找 | 每次将问题规模减半,执行次数对数增长 |
| O(n log n) | 快速排序、归并排序 | 递归分割问题,分割次数为对数,每次分割处理n个元素 |
| O(2^n) | 斐波那契递归 | 每个递归调用产生两个子问题,递归树的大小以指数方式增长 |
| O(n!) | 全排列问题 | 所有可能的排列组合,执行次数为阶乘级别 |
通过这些示例,掌握不同时间复杂度的算法可以帮助你在面对不同规模的数据时做出更高效的选择。
2. 常见时间复杂度分析经验总结(套路)
时间复杂度的分析是算法设计和优化的重要步骤。通过理解常见的时间复杂度模式,能够帮助我们快速估算算法的性能。以下是常见时间复杂度的分析经验和套路,帮助你快速做出判断。
2.1 O(1) — 常数时间复杂度
特点:
- 不依赖于输入数据的规模,操作次数固定。
- 常见于直接访问单个元素的操作,如数组或哈希表查找。
经验总结:
- 简单操作,例如返回数组的某个元素、单次赋值等。
- 如果程序只做一次简单的操作,不管数据规模有多大,时间复杂度通常是 O(1)。
典型示例:
def get_first_element(arr):
return arr[0]2.2 O(n) — 线性时间复杂度
特点:
- 执行时间与输入数据规模成正比。
- 常见于遍历整个数据结构或进行某些线性计算的场景。
经验总结:
- 遍历循环:若算法需要遍历数据结构中的每个元素(如列表、数组),通常时间复杂度为 O(n)。
- 简单的线性计算:例如对每个元素进行相同操作(求和、计数等)。
典型示例:
def sum_elements(arr):
total = 0
for num in arr:
total += num
return total2.3 — 平方时间复杂度
特点:
- 执行时间随着数据规模的增加呈平方增长,通常出现在嵌套循环的情况下。
- 常见于暴力解法,尤其是对二维数据或多维数组进行操作时。
经验总结:
- 嵌套循环:每一层循环的次数与输入规模相关,外层和内层循环都遍历 n 次时,时间复杂度通常为 O(n^2)。
- 二维数组处理:例如对一个矩阵的每个元素进行某些操作。
典型示例:
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]2.4 O(log n) — 对数时间复杂度
特点:
- 执行时间随着数据规模的增加而对数增长,通常出现在分治算法中,如二分查找。
- 每次操作都能将问题规模减少一半。
经验总结:
- 二分查找:排序数组中的元素时,查找的时间复杂度是 O(log n)。
- 分治算法:递归每次将问题规模缩小一半,时间复杂度通常是 O(log n)。
典型示例:
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -12.5 — 线性对数时间复杂度
特点:
- 执行时间随着数据规模的增加而线性增长,并且每次处理时需要做对数级别的操作。
- 常见于 分治算法(例如快速排序、归并排序)。
经验总结:
- 分治法:对一个问题进行分治处理,每次分解后对每个子问题递归处理,同时合并或排序时涉及 O(n) 操作。例如快速排序、归并排序等。
- 高效排序:归并排序、快速排序的时间复杂度是 O(n log n)。
典型示例:
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
while left and right:
if left[0] < right[0]:
result.append(left.pop(0))
else:
result.append(right.pop(0))
result.extend(left or right)
return result2.6 — 指数时间复杂度
特点:
- 执行时间随着输入规模的增加呈指数增长。
- 常见于递归解法,尤其是涉及 子集求解 或 排列组合 等问题。
经验总结:
- 递归树:每个递归调用都生成两个子问题,导致递归树的大小呈指数级增长。
- 排列组合问题:当需要穷举所有的排列、组合或子集时,时间复杂度通常是 O(2^n)。
典型示例:
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)2.7 O(n!) — 阶乘时间复杂度
特点:
- 执行时间随着数据规模的增加呈阶乘增长。
- 常见于需要生成所有排列或排列组合的情况。
经验总结:
- 排列问题:例如生成一个集合的所有排列时,可能需要计算 n! 种组合,因此时间复杂度为 O(n!)。
典型示例:
import itertools
def generate_permutations(arr):
return list(itertools.permutations(arr))2.8 总结:常见时间复杂度分析套路
2.8.1 基本分析:
- 单循环:一般是 O(n),每次遍历一个元素。
- 双重循环:通常是 ,嵌套循环每一层对每个元素进行操作。
- 递归:判断递归的分治结构,分解的次数和每次操作的复杂度。
- 对数递减:每次操作将问题规模缩小一半,通常是 O(log n)。
- 分治法:例如排序算法,通常是 O(n log n),合并操作 O(n),递归分解为 O(log n)。
- 暴力穷举:当需要遍历所有组合、排列等时,通常是 或 O(n!)。
2.8.2 递归树分析法:
- 绘制递归树,通过树的层数(通常是对数层数)和每一层的操作次数(通常是线性)来判断时间复杂度。
2.8.3 实际例子:
- 检查是否有嵌套循环,递归调用,或是分治处理等。
- 分析每个操作如何随数据规模变化,尤其是在大数据情况下,能显著影响程序的性能。
公众号:AI悦创【二维码】

AI悦创·编程一对一
AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发、Web、Linux」,招收学员面向国内外,国外占 80%。全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh
C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh
方法一:QQ
方法二:微信:Jiabcdefh

更新日志
0a693-于71ca1-于5dbbc-于