我长时间一直在摸不着头脑。我需要找到一个O(k)算法来查找min-heap是否比查询k
具有q
个更小的元素。
我尝试过这样的递归算法:
count = 0;
def kSmaller(H, q, k){
if (root(H) == Null or root(H) >= q ) return;
else {count++;
if (count == k) return true;
kSmaller(LeftChild(root(H), q, k)
kSmaller(RightChild(root(H), q, k)
}
}
但是在经历了一些最小堆的例子后,我无法理解如何在O(k)时间内终止,而不是不必要地遍历每个元素。
任何人都可以帮我理解如何处理这个问题吗?也许最好不要使用递归并将解决方案弄平。
答案 0 :(得分:2)
最小堆的排列方式是每个节点小于它的两个子树中的所有节点。因此,当您看到一个大于或等于q值的节点时,您会删除递归,因此您的代码将花费O(k)时间。您可以绘制一些示例并查看。如果Min堆的p节点小于q,那么你只需要min(p,k)时间,你能看到吗?
答案 1 :(得分:1)
另一种看到此算法实际上是O(k)时间的方法是:
让所有节点最初都是白色的。如果通过调用kSmaller()
来增加count
来访问节点,则将节点着色为黑色;如果通过调用kSmaller()
而不会增加count
来访问节点则为灰色}}。当count
没有递增时,递归停止,因此灰色节点下的每个节点都必须是白色; OTOH,黑色节点的每个孩子都必须是黑色或灰色。显然,确实存在count
个黑色节点,并且由于每个节点最多有2个子节点,因此最多可以有count * 2
个灰色节点,因此访问最多count * 3
个(即黑色或灰色)节点整体。由于count
显然始终保持< = k,因此访问的节点不超过3k。最后,由于每次调用只完成O(1)工作(在递归调用中花费的时间之外),总体时间复杂度最差为O(k)。