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

Posted

技术标签:

【中文标题】在 O(nlogk) 时间内找到长度为 n 的列表中总和小于 t 的 k 个元素【英文标题】:Finding k elements of length-n list that sum to less than t in O(nlogk) time 【发布时间】:2014-10-16 18:57:26 【问题描述】:

这是来自编程珍珠版。 2,第2栏,第8题:

给定一个由 n 个实数、一个实数 t 和一个整数 k 组成的集合,你能多快确定该集合中是否存在一个总和为 t 的 k 元素子集?

一个简单的解决方案是对前 k 个元素进行排序和求和,这是我们找到这样一个和的最大希望。然而,在解决方案部分,Bentley 提到了一个需要 nlog(k) 时间的解决方案,尽管他没有给出如何找到它的提示。我一直在为此苦苦挣扎;我的一个想法是遍历列表并添加小于 t/k 的所有元素(在 O(n) 时间内);假设有 m1

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)) 算法,但我很难向自己证明这一点。想法?

【问题讨论】:

我想我昨天或前一天看到了问题? 你是说这里吗?我环顾了一下,没有找到任何东西。 【参考方案1】:

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

【讨论】:

【参考方案2】:

考虑 t>0 和 all([x&gt;t for x in inList]) 的示例。 toJoin 永远是空的,你的算法甚至都没有完成,更不用说在 O(nlog(k)) 中了。

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

【讨论】:

很好,感谢您指点我一堆!我修改了我的代码来捕捉这种情况;为了了解,我将研究其最坏情况下的性能。

以上是关于在 O(nlogk) 时间内找到长度为 n 的列表中总和小于 t 的 k 个元素的主要内容,如果未能解决你的问题,请参考以下文章

在 O(n) 时间内找到数组中的 10 个最大整数

长度为 N 的数组可以包含值 1,2,3 ... N^2。是不是可以在 O(n) 时间内排序?

是否有可能在比(n 选择 3)更好的时间内找到可以从长度列表中形成的三角形数量?

Python heapq 与预排序列表的排序速度

O(n) 时间内的滑动窗口最大值

如何找到最小 L 使得长度为 L 的 k 个给定段可以覆盖 n 个给定点?