【问题标题】:How is the asymptotic complexity of finding the Next Greater Element's linear time?寻找下一个大元素的线性时间的渐近复杂度如何?
【发布时间】:2014-07-25 00:41:25
【问题描述】:

我正在阅读an algorithm to get the Next Greater Element for each element of an array

该网站声称他们的代码在O(n) 时间运行,但我无法理解它。

从左到右完整遍历数组本身将花费O(n),除此之外,当我们遍历列表时,每个索引处可以有多个推送/弹出操作。

虽然推送/弹出操作需要恒定的时间,但如果每个索引元素平均调用 m 次,我们将有 O(m) 作为每个索引的推送/弹出操作的成本,导致 @ 987654326@ 作为总成本,现在由于推送/弹出操作的总数应该大约(或可能完全)等于n,我们可以说mn 大约(或可能完全)等于@987654329 @ 暗示 m 是一个常数。

我的理由对吗?

我自己的推理仍然没有适当的清晰度,除了验证/无效我的理由之外,有人可以提供更好的解释吗?

【问题讨论】:

  • 解释(格式不佳)在原帖的底部。 每个元素可能的“多个”推送/弹出可能具有与 N 无关的顶端固定常数。“最坏的情况发生在所有元素按降序排序时。如果元素按降序排序,那么每个元素最多被处理 4 次。”

标签: c algorithm stack asymptotic-complexity


【解决方案1】:

为了方便,这里复制的伪代码:

  1. 将第一个元素推入堆栈。
  2. 一一挑选其余元素,然后循环执行以下步骤。
    1. 将当前元素标记为下一个
    2. 如果堆栈不为空,则从堆栈中弹出一个元素并与 next 进行比较。
    3. 如果 next 大于弹出元素,则 next 是弹出元素的下一个更大元素。
    4. 在弹出的元素小于next 时继续从堆栈中弹出。 next 成为所有此类弹出元素的下一个更大元素
    5. 如果下一个小于弹出的元素,则将弹出的元素推回。
    6. next 压入堆栈[伪代码中缺少此步骤]
  3. 步骤 2 中的循环结束后,从堆栈中弹出所有元素并打印 -1 作为它们的下一个元素。

外部循环运行O(n) 次。

很明显,除了为弹出的元素完成的工作没有被推回(第 4 步,减去它处理的最后一个元素),循环迭代的其余部分是常数时间。

因此,任何不断被弹出并推回堆栈的元素都将包含在每次迭代的恒定时间内,在那里它被弹出和推回。

剩下的就是元素被弹出而不是被推回的时间,但显然每个元素只能发生一次,因此这总共占O(n)运行时间。

由于我们从不复制堆栈中的项目(我们从数组中推送每个元素一次,然后我们只在弹出后再次推送)堆栈中的元素不能超过n,所以最终step 最多花费O(n) 时间。

因此总运行时间为O(n + n + n) = O(n)


另一种推理方式:

我们在每次循环迭代期间最多执行 2 次推送操作(其中有 n 个)。

因此最多有2n 推送操作,因此也最多有2n 弹出操作(我们无法弹出未推送的元素)。

我们每次 push/pop 操作做的工作量是恒定的,而且每次循环迭代我们额外做的工作量是恒定的(忽略每次 push/pop 操作完成的工作),因此总运行时间是O(n + 4n) = O(n)

【讨论】:

    【解决方案2】:

    n 的每次迭代可能有 m 操作,但 m 仍然是一个常数,并且独立于 n

    对于n 的每次迭代,推送/弹出操作的数量是恒定的,因此它们不会影响算法的时间复杂度。

    【讨论】:

      猜你喜欢
      • 2015-08-29
      • 1970-01-01
      • 2016-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多