算法的时间复杂度和空间复杂度

271 阅读3分钟

一般来说,解决问题的方法不止一种,因此我们需要通过比较不同算法的性能,选择出最佳的算法。一个算法的好坏,我们可以从时间和空间两个维度去衡量,并且分为两个阶段,一是 「算法完成前的理论分析」,这时假设除算法之外的其他因素对算法的实现是没有影响的,时间、空间复杂度就属于理论分析阶段,二是 「算法完成后的实际分析」,这时算法消耗的实际时间与计算机的硬件水平相关。

一、时间、空间复杂度说明

1. 时间复杂度

一个算法花费的时间与算法中语句的执行次数成正比。一个算法中所有语句的总执行次数称为 「时间频度或语句频度」,记为T(n),其中n称为 「问题的规模」

当n不断变化时,它所呈现出的规律称之为时间复杂度。算法的时间复杂度反映了 「程序执行时间随输入规模增长而增长的量级 」,它只关注最高数量级,且与之系数也没有关系,例如,T(n)=n^2T(n)=5n^2 + n虽然算法的时间频度不一样,但他们的时间复杂度却是一样的。通常情况来说,比起空间复杂度,我们更加注重时间复杂度。

2. 空间复杂度

空间复杂度是 「表示算法的存储空间与数据规模之间的增长关系」。判断如下:

  • 算法中是否使用了额外空间来存储数据;
  • 这个额外空间的大小会不会随着n的变化而变化。

通常来说,只要算法不涉及 「动态分配」 的空间,以及 「递归、栈」 所需的空间,空间复杂度通常为 O(1)。一个一维数组a[n],随输入规模n的增大而增大,那么其空间复杂度为O(n),二维数组空间复杂度则为O(n^2)。

3. 常见的复杂度

将常见的时间、空间复杂度按数量级递增排序为:

  • 常数阶O(1):哈希表的查找(以空间换时间)

  • 对数阶O(logn) :二分查找

  • 线性阶O(n)

  • 线性对数阶O(nlogn)

「若一个算法的复杂度属于上面其中的一种,那么这个算法的时间效率较高」

  • 平方阶O(n^2)

  • 立方阶O(n^3)

  • 指数阶O(2^n)

  • 阶乘O(n!)

二、时间、空间复杂度的计算

复杂度的计算步骤如下:

(1)找出算法中的 「基本语句」

基本语句就是算法中执行次数最多的那条语句, 通常为最内层循环的循环体。

(2)计算基本语句的执行次数的 「数量级」

忽略所有低次幂和最高次幂的系数,只需关注基本语句执行次数的数量级。

(3)用大O记号表示算法的时间性能。

1. 递归复杂度

T(n) 的递推关系式有 T(n) = a * T(b / n) * f(n)。其中 n 表示问题规模, a 为递推的子问题数量, b/n 表示每个子问题的规模(假设每个子问题的规模基本一样),f(n) 为递推以外的计算工作。

O(n) 的计算方式: image.png

2. 常见场景的复杂度

  1. 时间复杂度 O(n^2)
  1. 时间复杂度 O(logn)
var i = 1;
while (i <= n) {
    i = i * 2;
}
  1. 时间复杂度 O(nlogn)

  2. 空间复杂度 O(n)

function fun(n) {
    var temp = [];  
    for (let i = 0; i < n; i++) {
        temp.push(i)
    }
}

参考blog:

一文弄懂算法的时间和空间复杂度分析