从二叉堆中查找第 k 个最小元素的 O(klogk) 时间算法

发布于 2024-12-08 06:36:14 字数 205 浏览 1 评论 0原文

我们有一个 n 节点二叉堆,其中包含 n 个不同的项(根部的最小项)。对于k<=n,找到一个O(klogk)时间算法来从堆中选择kth最小的元素。

O(klogn) 很明显,但无法找出 O(klogk) 。也许我们可以使用第二个堆,但不确定。

We have an n-node binary heap which contains n distinct items (smallest item at the root). For a k<=n, find a O(klogk) time algorithm to select kth smallest element from the heap.

O(klogn) is obvious, but couldn't figure out a O(klogk) one. Maybe we can use a second heap, not sure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

嘿哥们儿 2024-12-15 06:36:14

好吧,你的直觉是正确的,我们需要额外的数据结构来实现 O(klogk),因为如果我们只是在原始堆上执行操作,则 logn 项将保留在最终的复杂性中。

从目标复杂度 O(klogk) 猜测,我想创建并维护一个大小为 k 的堆来帮助我实现目标。您可能知道,以自上而下的方式构建大小为 k 的堆需要 O(klogk),这确实让我想起了我们的目标。

以下是我尝试达到 O(klogk) 的尝试(不一定优雅或高效):

  1. 我们创建一个新的最小堆,将其根初始化为原始堆的根。

  2. 我们通过删除当前根并将当前根的两个子代插入到原始堆中来更新新的最小堆。我们重复这个过程 k 次。

  3. 生成的堆将由 k 个节点组成,其根是原始堆中第 k 个最小的元素。

注意:新堆中的节点应该存储原始堆中对应节点的索引,而不是节点值本身。在步骤 2 的每次迭代中,我们实际上将一个又一个节点的网络添加到新堆中(一个删除,两个插入),其中 k 次迭代将产生大小为 k 的新堆。第i次迭代时,要删除的节点是原堆中第i个最小的元素。

时间复杂度:在每次迭代中,从新堆中删除一个元素并向新堆中插入两个元素需要 O(3logk) 时间。经过 k 次迭代后,O(3klogk) = O(klogk)。

希望这个解决方案对您有所启发。

Well, your intuition was right that we need extra data structure to achieve O(klogk) because if we simply perform operations on the original heap, the term logn will remain in the resulting complexity.

Guessing from the targeted complexity O(klogk), I feel like creating and maintaining a heap of size k to help me achieve the goal. As you may be aware, building a heap of size k in top-down fashion takes O(klogk), which really reminds me of our goal.

The following is my try (not necessarily elegant or efficient) in an attempt to attain O(klogk):

  1. We create a new min heap, initializing its root to be the root of the original heap.

  2. We update the new min heap by deleting the current root and inserting the two children of the current root in the original heap. We repeat this process k times.

  3. The resulting heap will consist of k nodes, the root of which is the kth smallest element in the original heap.

Notes: Nodes in the new heap should store indexes of their corresponding nodes in the original heap, rather than the node values themselves. In each iteration of step 2, we really add a net of one more node into the new heap (one deleted, two inserted), k iterations of which will result in our new heap of size k. During the ith iteration, the node to be deleted is the ith smallest element in the original heap.

Time Complexity: in each iteration, it takes O(3logk) time to delete one element from and insert two into the new heap. After k iterations, it is O(3klogk) = O(klogk).

Hope this solution inspires you a bit.

半夏半凉 2024-12-15 06:36:14

假设我们使用最小堆,因此根节点始终小于其子节点。

Create a sorted list toVisit, which contains the nodes which we will traverse next. This is initially just the root node.
Create an array smallestNodes. Initially this is empty.
While length of smallestNodes < k:
    Remove the smallest Node from toVisit
    add that node to smallestNodes
    add that node's children to toVisit

完成后,第 k 个最小节点位于smallestNodes[k-1] 中。

根据 toVisit 的实现,您可以在 log(k) 时间内插入并在常数时间内删除(因为您只删除最顶层的节点)。这使得总共 O(k*log(k)) 。

Assuming that we're using a minheap, so that a root node is always smaller than its children nodes.

Create a sorted list toVisit, which contains the nodes which we will traverse next. This is initially just the root node.
Create an array smallestNodes. Initially this is empty.
While length of smallestNodes < k:
    Remove the smallest Node from toVisit
    add that node to smallestNodes
    add that node's children to toVisit

When you're done, the kth smallest node is in smallestNodes[k-1].

Depending on the implementation of toVisit, you can get insertion in log(k) time and removal in constant time (since you're only removing the topmost node). That makes O(k*log(k)) total.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文