看B站UP主 图灵星球TuringPlanet 的视频做的笔记,原视频: 时间复杂度和空间复杂度,大O表示法【数据结构和算法入门2】
做完笔记发现原作者有详细文字教程:文字教程 ,于是又参考人家的教程将自己的笔记完善和修改了一下。
时间复杂度
一个算法的执行时间受很多因素的影响,(例如执行算法的机器的好坏),所以我们不能仅依靠算法的执行时间来判断算法的好坏。因此我们用“大O表示法”来描述算法的渐进时间复杂度:
T
(
n
)
=
O
(
f
(
n
)
)
T(n)=O(f(n))
T(n)=O(f(n))
其中
T
(
n
)
T(n)
T(n)表示渐进时间复杂度,
f
(
n
)
f(n)
f(n)表示代码执行次数,
O
O
O表示正比例关系。
两个例子
栗子1
for(let i=1;i<=n;i++)
x++;
上面这段代码的执行次数为 ( 2 + 3 N ) (2+3N) (2+3N) 次:
- i = 1 ; → i=1; → i=1;→ 执行 1 1 1次;
- i < = n i<=n i<=n, x + + x++ x++, n + + ; → n++; → n++;→ 执行 N N N次,共执行 3 N 3N 3N次;
- 最后还要执行一次 i < = n i<=n i<=n.
所以时间复杂度为: O ( 2 + 3 N ) = O ( N ) O(2+3N)=O(N) O(2+3N)=O(N)。
【问:为什么这样简化?】
【答:因为
O
O
O计算的是在
N
N
N趋于
+
∞
+ \infty
+∞时的情况,所以常数
2
2
2和倍数
3
3
3就没有意义了。】
计算复杂度时,取最高次项,并去掉该项的次数
栗子2
for(let i=1;i<=n;i++)
x++;
for(let i=1;i<=n;i++)
for(let j=1;j<=n;j++)
x++;
时间复杂度: O ( N + N 2 ) = O ( N 2 ) O(N+N^2)=O(N^2) O(N+N2)=O(N2)。【当 N → + ∞ N → + \infty N→+∞时, N N N远小于 N 2 N^2 N2】
常用的时间复杂度:
- 常数阶 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)
- K次方阶 O ( n k ) O(n^k) O(nk)
- 指数阶 O ( 2 n ) O(2^n) O(2n)
- 阶乘 O ( n ! ) O(n!) O(n!)
时间复杂度从上到下越来越大,即执行效率越来越低。
线性阶 O ( 1 ) O(1) O(1)
只要没有循环或递归等复杂逻辑,无论代码执行多少行,复杂度都为 O ( 1 ) O(1) O(1)。
let x=0;
let y=1;
let temp=x;
x=y;
y=temp;
上述代码执行时,消耗的时间不会随着特定变量的增长而增长,即使有几万行这样的代码,我们都可以用 O ( 1 ) O(1) O(1)来表示它的时间复杂度。
常数阶 O ( n ) O(n) O(n)
栗子1。
对数阶 O ( l o g n ) O(logn) O(logn)
let i=1;
while(i<n)
i*=2;
分析:计算跳出循环需要执行多少次。 2 k = n → k = l o g 2 n 2^k=n → k=log_2n 2k=n→k=log2n,因此复杂度为 O ( l o g n ) O(logn) O(logn)。
线性对数阶 O ( n l o g n ) O(nlogn) O(nlogn)
for(let i=0;i<=n;i++){
let x=1;
while(x<n){
x*=2;
}
}
分析:while
外面加了一层
n
n
n 次循环,所以复杂度为:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 。
平方阶 O ( n 2 ) O(n^2) O(n2)
for(let i=0;i<=n;i++){
for(let j=0;j<=n;j++)
x++;
}
分析:很容易得知复杂度为 O ( n 2 ) O(n^2) O(n2)。
- 如果把第二层循环中的 n n n 换为 m m m, 则复杂度为: O ( n m ) O(nm) O(nm)。
- 同理,如果是三层循环,那么复杂度为: O ( n 3 ) O(n^3) O(n3)。如果是 k k k 层循环,复杂度为: O ( n k ) O(n^k) O(nk)。
空间复杂度
空间复杂度:算法所需的内存空间增长的趋势。
常用的空间复杂度:
- O ( 1 ) O(1) O(1) 、 O ( n ) O(n) O(n) 、 O ( n 2 ) O(n^2) O(n2)。
- 空间复杂度用 S ( N ) S(N) S(N)代表。
O ( 1 ) O(1) O(1)空间复杂度
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,则算法空间复杂度为一个常量,可表示为 O(1):
let x = 0;
let y = 0;
x++;
y++;
O ( n ) O(n) O(n)空间复杂度
这段代创建了一个长度为 n n n 的数组,在循环中为其中的元素赋值。因此,这段代码的「空间复杂度」取决于 array 的长度,也就是 n n n,所以 S ( n ) = O ( n ) S(n) = O(n) S(n)=O(n) 。
var array = new Array(n); // n是数组长度
for(let i=0;i<n;i++)
array[i]=i;
O ( n 2 ) O(n^2) O(n2)空间复杂度
给一个 n × n n \times n n×n 的矩阵赋值时,空间复杂度为 O ( n 2 ) O(n^2) O(n2) 。