我tm拿个AI写的教程都比你铺天盖地收费的好😡你就收费吧谁能收的过你啊😡看个教程不是收费就是水文
好的,同学,我们现在来学习算法复杂度分析中常用的符号,主要包括大O符号、大Θ符号等等。 这些符号可以帮助我们简洁地描述算法运行时间和内存使用情况随输入规模增长的速度。

[第一页]

我们先来学习最常用的 大O符号 (Big O notation)

大O符号 (Big O notation): 用于描述算法运行时间的上限 (upper bound) 或者说最坏情况的增长速度。

概念解释

  • 算法运行时间: 指的是算法执行所需的时间。这通常不是一个精确的秒数,因为它会受到计算机硬件、编程语言等多种因素的影响。
  • 上限 (upper bound): 意味着算法的实际运行时间不会超过这个数量级。 也就是说,无论输入数据多么糟糕,算法的运行时间都不会比大O表示的增长速度更快。
  • 最坏情况: 指的是在所有可能的输入中,导致算法运行时间最长的那种输入情况。
  • 增长速度: 我们关注的是当输入规模(通常用 nnn 表示)变得非常大时,算法运行时间是如何增长的。

通俗理解

你可以把大O符号想象成一个“保证书”,它保证了你的算法在最糟糕的情况下也不会慢到某种程度。 它给出了算法性能的一个“天花板”。

定义

如果存在正常数 cccn0n_0n0,使得对于所有的 n≥n0n \ge n_0nn0,都有:

0≤f(n)≤c⋅g(n)0 \le f(n) \le c \cdot g(n)0f(n)cg(n)

则称 f(n)=O(g(n))f(n) = O(g(n))f(n)=O(g(n))

公式解释

  • f(n)f(n)f(n): 表示算法的运行时间(或者占用的内存空间),它是输入规模 nnn 的函数。
  • g(n)g(n)g(n): 是一个我们用来描述 f(n)f(n)f(n) 增长速度的函数,通常选择一些比较简单的函数,比如 nnn, n2n^2n2, log⁡n\log nlogn 等。
  • ccc: 是一个常数因子。
  • n0n_0n0: 是一个起始的输入规模,当输入规模大于 n0n_0n0 时,不等式才成立。
  • 这个定义说明,当输入规模 nnn 足够大时(大于等于 n0n_0n0),f(n)f(n)f(n) 的值总是小于等于 ccc 乘以 g(n)g(n)g(n)。也就是说,g(n)g(n)g(n) 给出了 f(n)f(n)f(n) 的一个上界,忽略了常数因子 ccc 和较小的输入规模。

举个例子

假设一个算法的实际运行时间是 f(n)=3n2+2n+10f(n) = 3n^2 + 2n + 10f(n)=3n2+2n+10

我们可以说这个算法的运行时间是 O(n2)O(n^2)O(n2)。 为什么呢?

我们可以找到常数 c=4c = 4c=4n0=3n_0 = 3n0=3,使得对于所有的 n≥3n \ge 3n3,都有:

3n2+2n+10≤4n23n^2 + 2n + 10 \le 4n^23n2+2n+104n2

你可以自己代入一些大于等于 3 的 nnn 值验证一下。

常见的大O时间复杂度(按增长速度从小到大排列):

  • O(1): 常数时间复杂度。 算法的运行时间不随输入规模的增长而变化。 比如,访问数组的某个特定元素。
  • O(log n): 对数时间复杂度。 算法的运行时间随着输入规模的对数增长而增长。 比如,二分查找。
  • O(n): 线性时间复杂度。 算法的运行时间随着输入规模的线性增长而增长。 比如,遍历一个数组。
  • O(n log n): 线性对数时间复杂度。 比如,归并排序,快速排序的平均情况。
  • O(n^2): 平方时间复杂度。 算法的运行时间随着输入规模的平方增长而增长。 比如,冒泡排序,插入排序。
  • O(2^n): 指数时间复杂度。 算法的运行时间随着输入规模的指数增长而增长。 这类算法通常效率很低,只适用于很小的输入规模。 比如,暴力枚举所有子集。
  • O(n!): 阶乘时间复杂度。 比指数时间复杂度增长得还要快,非常低效。 比如,旅行商问题的暴力解法。

[第二页]

接下来,我们来学习 大Θ符号 (Big Theta notation)

大Θ符号 (Big Theta notation): 用于描述算法运行时间的紧确界 (tight bound) 或者说平均情况的增长速度。

概念解释

  • 紧确界 (tight bound): 意味着算法的运行时间既有上界也有下界,并且上界和下界的增长速度是相同的。 也就是说,算法的运行时间增长速度与大Θ表示的增长速度是相同的。
  • 平均情况: 通常指的是算法在各种可能的输入情况下运行时间的平均水平。

通俗理解

你可以把大Θ符号想象成一个“双向保证书”,它保证了你的算法不会太慢,也不会太快,它的运行速度就稳定在这个数量级。 它给出了算法性能的一个更精确的描述。

定义

如果存在正常数 c1c_1c1, c2c_2c2n0n_0n0,使得对于所有的 n≥n0n \ge n_0nn0,都有:

0≤c1⋅g(n)≤f(n)≤c2⋅g(n)0 \le c_1 \cdot g(n) \le f(n) \le c_2 \cdot g(n)0c1g(n)f(n)c2g(n)

则称 f(n)=Θ(g(n))f(n) = \Theta(g(n))f(n)=Θ(g(n))

公式解释

  • 这个定义说明,当输入规模 nnn 足够大时(大于等于 n0n_0n0),f(n)f(n)f(n) 的值被 c1⋅g(n)c_1 \cdot g(n)c1g(n)c2⋅g(n)c_2 \cdot g(n)c2g(n) 夹在中间。也就是说,g(n)g(n)g(n) 给出了 f(n)f(n)f(n) 的一个既是上界又是下界的紧确界,同样忽略了常数因子和较小的输入规模。

与大O符号的区别

大O符号只给出了算法运行时间的上限,而大Θ符号给出了算法运行时间的紧确界。 如果一个算法的运行时间是 Θ(n2)\Theta(n^2)Θ(n2),那么它一定是 O(n2)O(n^2)O(n2),但反过来不成立。 一个算法的运行时间是 O(n2)O(n^2)O(n2),它可能实际是 Θ(n2)\Theta(n^2)Θ(n2),也可能是 Θ(n)\Theta(n)Θ(n),甚至 Θ(log⁡n)\Theta(\log n)Θ(logn)

举个例子

对于之前的算法,如果它的运行时间总是接近 3n23n^23n2,那么我们就可以说它的运行时间是 Θ(n2)\Theta(n^2)Θ(n2)

我们可以找到常数 c1=2c_1 = 2c1=2, c2=4c_2 = 4c2=4n0=3n_0 = 3n0=3,使得对于所有的 n≥3n \ge 3n3,都有:

2n2≤3n2+2n+10≤4n22n^2 \le 3n^2 + 2n + 10 \le 4n^22n23n2+2n+104n2

[第三页]

除了大O符号和大Θ符号,还有一些其他的符号也经常用于算法复杂度分析,虽然不如前面两个常用,但了解一下也有好处。

  • 大Ω符号 (Big Omega notation): 用于描述算法运行时间的下限 (lower bound) 或者说最好情况的增长速度。

    定义

    如果存在正常数 cccn0n_0n0,使得对于所有的 n≥n0n \ge n_0nn0,都有:

    0≤c⋅g(n)≤f(n)0 \le c \cdot g(n) \le f(n)0cg(n)f(n)

    则称 f(n)=Ω(g(n))f(n) = \Omega(g(n))f(n)=Ω(g(n))

    通俗理解: 大Ω符号给出了算法性能的一个“地板”,保证了算法的运行时间不会低于某个增长速度。

  • 小o符号 (Small o notation): 类似于大O符号,但它表示的是非紧的上界 (non-tight upper bound)

    定义

    对于任意正常数 c>0c > 0c>0,都存在正常数 n0n_0n0,使得对于所有的 n≥n0n \ge n_0nn0,都有:

    0≤f(n)<c⋅g(n)0 \le f(n) < c \cdot g(n)0f(n)<cg(n)

    则称 f(n)=o(g(n))f(n) = o(g(n))f(n)=o(g(n))

    通俗理解: 如果 f(n)=o(g(n))f(n) = o(g(n))f(n)=o(g(n)),意味着当 nnn 趋近于无穷大时,f(n)g(n)\frac{f(n)}{g(n)}g(n)f(n) 趋近于 0。 也就是说,f(n)f(n)f(n) 的增长速度远慢于 g(n)g(n)g(n)。 比如,n=o(n2)n = o(n^2)n=o(n2)

  • 小ω符号 (Small omega notation): 类似于大Ω符号,但它表示的是非紧的下界 (non-tight lower bound)

    定义

    对于任意正常数 c>0c > 0c>0,都存在正常数 n0n_0n0,使得对于所有的 n≥n0n \ge n_0nn0,都有:

    0≤c⋅g(n)<f(n)0 \le c \cdot g(n) < f(n)0cg(n)<f(n)

    则称 f(n)=ω(g(n))f(n) = \omega(g(n))f(n)=ω(g(n))

    通俗理解: 如果 f(n)=ω(g(n))f(n) = \omega(g(n))f(n)=ω(g(n)),意味着当 nnn 趋近于无穷大时,f(n)g(n)\frac{f(n)}{g(n)}g(n)f(n) 趋近于无穷大。 也就是说,f(n)f(n)f(n) 的增长速度远快于 g(n)g(n)g(n)。 比如,n2=ω(n)n^2 = \omega(n)n2=ω(n)

总结一下

符号 含义 类似比喻
OOO 上界/最坏情况 天花板
Θ\ThetaΘ 紧确界/平均情况 通道
Ω\OmegaΩ 下界/最好情况 地板
ooo 非紧的上界 远低于天花板
ω\omegaω 非紧的下界 远高于地板

在实际应用中,大O符号是最常用的,因为它能帮助我们评估算法在最坏情况下的性能,从而避免选择效率过低的算法。 大Θ符号则能更精确地描述算法的平均性能。

希望这些解释能够帮助你理解算法复杂度分析中的这些符号。 理解这些符号是学习算法和数据结构的重要基础。 你都明白了吗?

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐