【问题标题】:What would cause an algorithm to have O(log log n) complexity?什么会导致算法具有 O(log log n) 复杂度?
【发布时间】:2013-05-09 22:13:54
【问题描述】:

This earlier question 解决了一些可能导致算法具有 O(log n) 复杂度的因素。

什么会导致算法的时间复杂度为 O(log log n)?

【问题讨论】:

    标签: algorithm big-o time-complexity complexity-theory logarithm


    【解决方案1】:

    O(log log n) 项可以出现在各种不同的地方,但通常有两条主要路线会到达此运行时。

    按平方根收缩

    正如对链接问题的回答中所提到的,算法具有 O(log n) 时间复杂度的一种常见方法是让该算法通过在每次迭代中将输入的大小重复减小某个常数因子来工作.如果是这种情况,算法必须在 O(log n) 次迭代后终止,因为在 O(log n) 除以常数之后,算法必须将问题大小缩小到 0 或 1。这就是为什么,例如, 二分查找的复杂度为 O(log n)。

    有趣的是,有一种类似的方法可以缩小问题的大小,从而产生 O(log log n) 形式的运行时。不是在每一层将输入分成两半,如果我们在每一层取大小的平方根会发生什么?

    例如,我们以数字 65,536 为例。我们必须将其除以 2 多少次才能降到 1?如果我们这样做,我们会得到

    • 65,536 / 2 = 32,768
    • 32,768 / 2 = 16,384
    • 16,384 / 2 = 8,192
    • 8,192 / 2 = 4,096
    • 4,096 / 2 = 2,048
    • 2,048 / 2 = 1,024
    • 1,024 / 2 = 512
    • 512 / 2 = 256
    • 256 / 2 = 128
    • 128 / 2 = 64
    • 64 / 2 = 32
    • 32 / 2 = 16
    • 16 / 2 = 8
    • 8 / 2 = 4
    • 4 / 2 = 2
    • 2 / 2 = 1

    这个过程需要16个步骤,65536 = 216也是如此。

    但是,如果我们在每个级别上取平方根,我们会得到

    • √65,536 = 256
    • √256 = 16
    • √16 = 4
    • √4 = 2

    请注意,只需四个步骤即可一直到 2。这是为什么呢?

    首先,一个直观的解释。数字 n 和 √n 有多少位数字?数 n 中大约有 log n 位,在 √n 中大约 log (√n) = log (n1/2) = (1/2) log n 位。这意味着,每次取平方根时,数字中的位数大致减半。因为你只能将一个数量 k O(log k) 减半,然后它会下降到一个常数(比如 2),这意味着你只能在减少数字之前取平方根 O(log log n) 次到某个常数(比如 2)。

    现在,让我们进行一些数学运算以使其更加严谨。让我们用 2 的幂来重写上面的序列:

    • √65,536 = √216 = (216)1/2 = 28 = 256
    • √256 = √28 = (28)1/2 = 24 = 16
    • √16 = √24 = (24)1/2 = 22 = 4
    • √4 = √22 = (22)1/2 = 21 = 2

    注意我们遵循的顺序是 216 → 28 → 24 → 22 → 2 1。在每次迭代中,我们将二的幂的指数减半。这很有趣,因为这与我们已经知道的有关——在它降至零之前,您只能将数字 k 除以 O(log k) 次。

    所以取任意数 n 并将其写为 n = 2k。每次取 n 的平方根时,都会将这个方程中的指数减半。因此,在 k 降至 1 或更低(在这种情况下,n 降至 2 或更低)之前,只能应用 O(log k) 平方根。由于 n = 2k,这意味着 k = log2 n,因此所取的平方根数为 O(log k) = O(log log n) .因此,如果有算法通过反复将问题缩减为大小为原始问题大小的平方根的子问题,则该算法将在 O(log log n) 步后终止。

    van Emde Boas tree(vEB-tree)数据结构就是一个真实的例子。 vEB-tree 是一种专门的数据结构,用于存储 0 ... N - 1 范围内的整数。它的工作原理如下:树的根节点中有 √N 个指针,分割范围 0 ... N - 1 到 √N 个桶中,每个桶包含大约 √N 个整数的范围。然后这些桶在内部被细分为 √(√ N) 个桶,每个桶大约包含 √(√ N) 个元素。要遍历树,您从根开始,确定您属于哪个存储桶,然后递归地在适当的子树中继续。由于 vEB 树的结构方式,您可以在 O(1) 时间内确定要下降到哪个子树,因此在 O(log log N) 步之后,您将到达树的底部。因此,在 vEB-tree 中查找只需要 O(log log N) 时间。

    另一个例子是Hopcroft-Fortune closest pair of points algorithm。该算法试图在二维点集合中找到两个最近的点。它通过创建一个桶网格并将点分布到这些桶中来工作。如果在算法中的任何点发现一个桶中包含超过 √N 个点,则该算法递归地处理该桶。因此,递归的最大深度是 O(log log n),并且使用对递归树的分析可以证明树中的每一层都做了 O(n) 的工作。因此,算法的总运行时间为 O(n log log n)。

    O(log n) 小输入算法

    还有一些其他算法通过对大小为 O(log n) 的对象使用二进制搜索等算法来实现 O(log log n) 运行时。例如,x-fast trie 数据结构在高度为 O(log U) 的 at 树的层上执行二进制搜索,因此它的一些操作的运行时间为 O(log log U)。相关的y-fast trie 通过维护每个 O(log U) 节点的平衡 BST 来获得一些 O(log log U) 运行时,从而允许在这些树中的搜索在 O(log log U) 时间内运行。 tango tree 和相关的 multisplay tree 数据结构在他们的分析中以 O(log log n) 项结束,因为它们维护的树每个都包含 O(log n) 项。

    其他例子

    其他算法以其他方式实现运行时间 O(log log n)。 Interpolation search 期望运行时 O(log log n) 在排序数组中找到一个数字,但分析相当复杂。最终,分析表明迭代次数等于数 k 使得 n2-k ≤ 2,其中 log log n 是正确的解决方案.一些算法,如Cheriton-Tarjan MST algorithm,通过解决复杂的约束优化问题,达到了涉及 O(log log n) 的运行时。

    希望这会有所帮助!

    【讨论】:

    • @JonathonReinhart- 这恰好是我认为 (a) 非常非常酷,并且 (b) 不为人所知的事情。我总是很高兴分享这样的事情! :-)
    • 只是猜测页面底部的“回答你自己的问题”可能有什么其他含义,或者它只是在问题页面上启用答案文本框。
    • 重要的一行:因此,如果有算法通过重复将问题减少到大小为原始问题大小的平方根的子问题来工作,那么该算法将在 O(log log n ) 步骤。
    【解决方案2】:

    在时间复杂度中查看 O(log log n) 因子的一种方法是像其他答案中解释的那样通过除法,但是当我们想要在时间和空间/时间和近似/时间和硬度/...算法,我们对我们的算法进行了一些人工迭代。

    例如 SSSP(Single source shortest path) 在平面图上有一个 O(n) 算法,但在那个复杂的算法之前有一个更简单的算法(但仍然相当困难),运行时间为 O(n log log n ),算法的基础如下(只是非常粗略的描述,我建议跳过理解这部分并阅读答案的另一部分):

    1. 将图形分成大小为 O(log n/(log log n)) 的部分,但有一些限制。
    2. 假设每个提到的部分都是新图 G' 中的节点,然后在 O(|G'|*log |G'|) ==> 这里计算 G' 的 SSSP,因为 |G'| = O(|G|*log log n/log n) 我们可以看到 (log log n) 因子。
    3. 计算每个部分的 SSSP:再次因为我们有 O(|G'|) 部分,我们可以及时计算所有部分的 SSSP |n/logn| * |log n/log logn * log (logn /log log n)。
    4. 更新权重,这部分可以在 O(n) 内完成。 更多详情this lecture notes 很好。

    但我的意思是,这里我们选择大小为 O(log n/(log log n)) 的除法。如果我们选择像 O(log n/ (log log n)^2) 这样的其他划分,它可能会运行得更快并带来另一个结果。我的意思是,在很多情况下(比如在近似算法或随机算法中,或者像上面的 SSSP 算法),当我们迭代某些东西(子问题,可能的解决方案,......)时,我们选择与该交易相对应的迭代次数我们有(时间/空间/算法的复杂性/算法的常数因子,...)。所以我们可能会在实际工作算法中看到比“log log n”更复杂的东西。

    【讨论】:

      猜你喜欢
      • 2012-02-27
      • 1970-01-01
      • 1970-01-01
      • 2011-07-09
      • 2015-06-12
      • 1970-01-01
      • 2018-11-26
      • 2021-11-11
      • 1970-01-01
      相关资源
      最近更新 更多