我有一个带n
个元素的最小堆,想要从这个堆中找到k
个最小的数字。什么是最坏情况的复杂性?
这是我的方法:在stackoverflow的某个地方,我读到在最小堆中找到第i个最小数字的复杂性是O(i)
。因此,如果我们想找到n-1
最小的数字(n是没有意义的,因为它将是整个堆),总复杂度看起来像这样:
O(n-1)+O(n-2)+O(n-3)+…+O(2)+O(1)=O((1+n-1)*(n/2))=O(n^2)
这是对的吗?
答案 0 :(得分:4)
不,时间比那更好。 O(k log(n))
非常容易,O(k)
如果你聪明的话。
从堆中查找和删除最小元素是O(log(n))
。这很容易导致O(k log(n))
时间。
但您正在考虑的结果是https://ac.els-cdn.com/S0890540183710308/1-s2.0-S0890540183710308-main.pdf?_tid=382a1cac-e4f7-11e7-8ac9-00000aab0f02&acdnat=1513713791_08f4df78a8821855e8ec788da063ea2f,它显示了如何及时找到k
最小数字O(k)
的大小。现在,您使用堆是二叉树的事实,并从根开始,并对您找到的小于最大值的每个数字进行递归搜索。然后使用k
'最小号码的副本填写列表的其余部分。
在该搜索中,您最终会看到最多这个尺寸的所有k
,对于其中一些,您会看到最多2个太大而无法打扰的父母,最多3k
元素。这使得整个搜索O(k)
。
答案 1 :(得分:2)
我怀疑是否有可能及时识别出 O(k) 中的 k 最小元素。我之前看到的最好的是 O(k log k)算法,它还可以通过识别 k 最小元素来方便地解决您的问题。您可以在another answer on StackOverflow或Quora上阅读详细信息。
基本思想是操纵辅助堆。最初,此辅助堆仅包含原始堆的根。在每个步骤中,算法都会删除辅助堆的min,并将其两个原始子项(即其子项从原始堆)插入到辅助堆中。
这个算法有一个很好的属性,在步骤 i ,它从辅助堆中删除的元素是整个 i 最小的元素。因此,在 k 步骤之后,已从辅助堆中删除的项集恰好是 k 最小元素。该算法是 O(k log k)因为 O(k)删除/插入到二级堆中,其大小上限为 O(k )
编辑:我的立场得到了纠正! btilly的回答使用this paper的结果在 O(k)中提供了解决方案。