算法时间复杂度
一、什么是时间复杂度
描述算法的运行时间,常用大O符号表述,表示算法的执行时间和算法的输入值之间的关系
例如:
def aFunc(n):
sum = 0
for i in range(n): # 执行时间a
sum += i # 执行时间b
return sum # 执行时间c
总共执行时间:a+n*b+c
只保留最高次项,也不关心系数,所以这个的时间复杂度是
O
(
n
)
O(n)
O(n)
常见的时间复杂度高低排序: O ( 1 ) O(1) O(1)< O ( l o g n ) O(logn) O(logn)< O ( n ) O(n) O(n)< O ( n l o g n ) O(nlogn) O(nlogn)< O ( n 2 ) O(n^2) O(n2)< O ( n 3 ) O(n^3) O(n3)< O ( 2 n ) O(2^n) O(2n)< O ( n ! ) O(n!) O(n!)
常见时间复杂度分析:
(1)常数阶
O
(
1
)
O(1)
O(1)
O
(
1
)
O(1)
O(1),表示该算法的执行时间(或执行时占用空间)总是为一个常量,不论输入的数据集是大是小,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是
O
(
1
)
O(1)
O(1),如:
i = 1
j = 2
print('Hello World')
上述代码在执行的时候,它消耗的时候并不随着某个变量的增长而增长,那么无论这类代码有多长,即使有几万几十万行,都可以用 O ( 1 ) O(1) O(1)来表示它的时间复杂度
(2)线性阶
O
(
n
)
O(n)
O(n)
O
(
n
)
O(n)
O(n),表示一个算法的性能会随着输入数据的大小变化而线性变化,如:
for i in range(n):
print('Hello world')
这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用 O ( n ) O(n) O(n)来表示它的时间复杂度
(3)平方阶
O
(
n
2
)
O(n^2)
O(n2)
O
(
n
)
O(n)
O(n) 表示一个算法的性能将会随着输入数据的增长而呈现出二次增长。最常见的就是对输入数据进行嵌套循环。如果嵌套层级不断深入的话,算法的性能将会变为立方阶
O
(
n
3
)
O(n3)
O(n3),
O
(
n
4
)
O(n4)
O(n4),
O
(
n
k
)
O(n^k)
O(nk)以此类推
for i in range(n): # O(n^2)
for j in range(n):
print('Hello world')
(4)指数阶
O
(
2
n
)
O(2^n)
O(2n)
O
(
2
n
)
O(2^n)
O(2n),表示一个算法的性能会随着输入数据的每次增加而增大两倍,典型的方法就是裴波那契数列的递归计算实现
n = 6
def fib(n):
if n<2:return n
return fib(n-1)+fib(n-2)
print('斐波拉契',n,'为:',fib(n))
(5)对数阶 O ( l o g n ) O(logn) O(logn)
def Ologn(num):
i = 1
while(i < num):
i = i * 2
return i
因为每次count*2后,距离结束循环更近了。也就是说有多少个2 相乘后大于n,退出循环。
数学公式: 2 x 2^x 2x = n --> x = l o g 2 n log2n log2n
因此这个循环的时间复杂度为 O ( l o g n ) O(logn) O(logn)
(6)线性对数阶
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
线性对数阶
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) ,就是将时间复杂度为对数阶
O
(
l
o
g
n
)
O(logn)
O(logn)的代码循环n遍的话,那么它的时间复杂度就是 n *
O
(
l
o
g
n
)
O(logn)
O(logn),也就是了
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
二、什么是空间复杂度
是对一个算法在运行过程中临时占用存储空间大小的量度,是算法的存储空间与输入值之间的关系
常见空间复杂度分析:
一般看变量变量类型或者有无递归
(1)
O
(
1
)
O(1)
O(1)
定义一个或多个变量,空间复杂度都是为1
def test(n):
sum = 0
for i in range(n):
sum += i
return sum
(2) O ( n ) O(n) O(n)
def test(nums):
array = []
for num in nums:
array.append(num)
return array
列表的空间复杂度为列表的长度
如果代码开了数组,则为数组长度
如果有递归,则为递归深度
如果有数组有递归,取最大值
三、总结
一般我们写算法,时间复杂度和空间复杂度只能二选一,有时拿时间换空间,有时空间换时间。
面试:告诉面试官时间最优和空间最优
工作:一般选时间最优