算法是独立存在的一种解决问题的方法和思想,与程序和语言没有必然关系,任何语言都可以用来描述算法的实现。
如果a+b+c=1000,且 a 2 + b 2 = c 2 a^{2}+b^{2}=c^{2} a2+b2=c2(a、b、c为自然数),如何求出所有a、b、c可能的组合?
// 本地运行162.42s
import time
start_time = time.time()
for a in range(0,1001):
for b in range(0,1001):
for c in range(0,1001):
if a + b + c == 1000 and a**2 + b**2 == c**2:
print("a,b,c=",a,b,c)
end_time = time.time()
print("time:%.2f"%(end_time-start_time))
// 本地运行1.55s
import time
start_time = time.time()
for a in range(0,1001):
for b in range(0,1001):
c = 1000 - a - b
if a + b + c == 1000 and a**2 + b**2 == c**2:
print("a,b,c=",a,b,c)
end_time = time.time()
print("time:%.2f"%(end_time-start_time))
相同的代码运行在不同的平台上会有不同的效率,所以用时间来衡量一段代码的执行效率是不可靠的。
因此提出了时间复杂度与“大O记法”,用来衡量代码执行基本运算的数量。
通常把一行代码作为一步,不进行继续细分。并将步骤进行进一步抽象,得到与问题规模N有关的复杂度。
执行次数 | 时间复杂度 | 非正式术语 |
---|---|---|
12 12 12 | O ( 1 ) O(1) O(1) | 常数阶 |
2 n + 3 2n+3 2n+3 | O ( n ) O(n) O(n) | 线性阶 |
3 2 + 2 n + 1 3^{2}+2n+1 32+2n+1 | O ( n 2 ) O(n^{2}) O(n2) | 平方阶 |
5 l o g 2 n + 2 = 5log_{2}n+2= 5log2n+2= | O ( l o g n ) O(logn) O(logn) | 对数阶 |
2 n + 3 n l o g 2 n + 19 2n+3nlog_{2}n+19 2n+3nlog2n+19 | O ( n l o g n ) O(nlogn) O(nlogn) | nlog阶 |
6 n 3 + 2 n 2 + 3 n + 4 6n^{3}+2n^{2}+3n+4 6n3+2n2+3n+4 | O ( n 3 ) O(n^{3}) O(n3) | 立方阶 |
2 n 2^{n} 2n | O ( 2 n ) O(2^{n}) O(2n) | 指数阶 |
O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1) < O(logn) < O(n) < O(nlogn) < O(n^{2}) < O(n^{3}) < O(2^{n}) < O(n!) < O(n^{n}) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
T = 1000*1000*1000*2
T(n) = n^3*2
g(n) = n^3 相比T函数,省去了系数和常数,称为T函数的渐进函数,也就是该程序的大O表示法
g(n) = O(n^2)
// T = 1000*1000*1000*2
// T = n*n*n*2
// T(n) = n^3*2
// g(n) = n^3 相比T函数,省去了系数和常数,称为T函数的渐进函数,也就是该程序的大O表示法
for a in range(0,1001):
for b in range(0,1001):
for c in range(0,1001):
if a + b + c == 1000 and a**2 + b**2 == c**2:
print("a,b,c=",a,b,c)
数据的不同,常常决定了时间复杂度的不同。
例如对两个列表升序排序:
a = [5,4,3,2,1]
b = [1,2,3,4,5]
时间复杂度一定是不同的。
因此,算法存在: