查找长度为n的列表中的k个元素,在O(nlogk)时间内总和小于t

时间:2014-08-22 20:36:24

标签: algorithm programming-pearls

这是来自Programming Pearls ed。 2,第2栏,问题8:

给定一组n个实数,一个实数t和一个整数k,你能多快判断该组中是否存在一个总和最多为t的k元素子集?

一个简单的解决方案是对前k个元素进行排序和求和,这是我们找到这样一个总和的最佳希望。然而,在解决方案部分,Bentley暗示了一个采用nlog(k)时间的解决方案,尽管他没有给出如何找到它的提示。我一直在努力奋斗;一个人认为我要通过列表并添加所有小于t / k的元素(在O(n)时间内);说有m1< k这样的元素,它们总和为s1<吨。然后我们需要k-m1元素,所以我们可以在O(n)时间内再次扫描列表,查找小于(t-s1)/(k-m1)的所有元素。再次加入,得到s2和m2,然后再次加上m2< k,寻找小于(t-s2)/(k-m2)的所有元素。所以:

def kSubsetSumUnderT(inList, k, t):
    outList = []
    s = 0
    m = 0
    while len(outList) < k:
        toJoin = [i for i in inList where i < (t - s)/(k - m)]
        if len(toJoin):
            if len(toJoin) >= k - m:
                toJoin.sort()
                if(s + sum(toJoin[0:(k - m - 1)]) < t:
                    return True
                return False
            outList = outList + toJoin
            s += sum(toJoin)
            m += len(toJoin)
        else:
            return False

我的直觉是这可能是O(nlog(k))算法,但我很难向自己证明这一点。想法?

2 个答案:

答案 0 :(得分:2)

考虑t> 0和all([x>t for x in inList])的示例。 toJoin将永远为空,您的算法甚至无法完成,更不用说O(nlog(k))。

您可能缺少的提示是http://en.wikipedia.org/wiki/Heap_(data_structure)

答案 1 :(得分:0)

运行时间Theta(n log k)的自然算法可能是用k个无穷大初始化最大堆,然后遍历数组,推送新元素并弹出最大值以使堆中的k最小结束。 (正如Bentley所提到的,在Theta(n)时间选择渐近更快。在实践中选择的最佳方法可能是堆积并弹出最小k次,即Theta(n + k log n)= Theta(n)当k = O(n / log n)时。)