计算列表中 k 个最大数字之和的有效方法?
Efficient way to compute sum of k largest numbers in a list?
我正在阅读一些面试练习题,对此我有疑问。假设一个随机整数列表,每个整数介于 1 和 100 之间,计算 k 个最大整数的总和?讨论 space 和时间复杂度,如果每个整数都在 1 和 m 之间(其中 m 变化),方法是否会改变?
我的第一个想法是对数组进行排序并计算最大的 k 个数字的总和。然后,我想如果我使用一个二叉树结构,我可以从右下角的树开始看。我不确定我的方法是否会改变数字是 1 到 100 还是 1 到 m?有什么最有效的方法吗?
最有效的方法可能是使用类似 randomized quickselect 的方法。它不会执行排序步骤直至完成,而只是执行快速排序的分区步骤。如果您不希望以某种特定顺序出现 k 个最大整数,这就是我要采用的方式。它需要线性时间,但分析不是很简单。 m 对此影响不大。此外,您可以编写代码,在对数组进行分区时计算总和。
Time: O(n)
Space: O(1)
备选方案 正在使用类似counting sort 的方法进行排序,它具有线性时间保证。正如您所说的值是固定范围内的整数,它会工作得很好。随着 m 的增加,space 要求上升,但在桶内计算总和非常有效。
Time: O(m) in the worst case (see comments for the argument)
Space: O(m)
我想说排序可能是不必要的。如果 k
很小,那么您需要做的就是维护一个排序列表,该列表截断第 k
个最大元素之外的元素。
其中的每一步都应该是 O(k)
在最坏的可能情况下,即添加的元素被最大化。然而,一般情况下情况要好得多,在一定数量的元素之后,大多数应该小于列表中的最后一个元素并且操作将是 O(log(k))
.
一种方法是使用最大大小为 k 的 min-heap (implemented as a binary tree)。查看一个新元素是否属于堆的时间复杂度为 O(1),因为它是一个最小堆,并且检索最小元素是一个常数时间操作。 O(n) 列表中的每个插入步骤(或非插入......在元素太小而无法插入的情况下)是 O(log k)。最后的树遍历和求和步骤是 O(k)。
总复杂度:
O (n log k + k) = O(n log k)
)
除非你的计算机上有多个内核运行,在这种情况下,并行计算是一种选择,求和应该只在最后进行。即时计算会增加额外的计算步骤,而实际上根本不会降低您的时间复杂度(您实际上会有更多的计算要做)。无论如何,您总是需要对 k 个元素求和,那么为什么不避免额外的加法和减法步骤呢?
我正在阅读一些面试练习题,对此我有疑问。假设一个随机整数列表,每个整数介于 1 和 100 之间,计算 k 个最大整数的总和?讨论 space 和时间复杂度,如果每个整数都在 1 和 m 之间(其中 m 变化),方法是否会改变?
我的第一个想法是对数组进行排序并计算最大的 k 个数字的总和。然后,我想如果我使用一个二叉树结构,我可以从右下角的树开始看。我不确定我的方法是否会改变数字是 1 到 100 还是 1 到 m?有什么最有效的方法吗?
最有效的方法可能是使用类似 randomized quickselect 的方法。它不会执行排序步骤直至完成,而只是执行快速排序的分区步骤。如果您不希望以某种特定顺序出现 k 个最大整数,这就是我要采用的方式。它需要线性时间,但分析不是很简单。 m 对此影响不大。此外,您可以编写代码,在对数组进行分区时计算总和。
Time: O(n)
Space: O(1)
备选方案 正在使用类似counting sort 的方法进行排序,它具有线性时间保证。正如您所说的值是固定范围内的整数,它会工作得很好。随着 m 的增加,space 要求上升,但在桶内计算总和非常有效。
Time: O(m) in the worst case (see comments for the argument)
Space: O(m)
我想说排序可能是不必要的。如果 k
很小,那么您需要做的就是维护一个排序列表,该列表截断第 k
个最大元素之外的元素。
其中的每一步都应该是 O(k)
在最坏的可能情况下,即添加的元素被最大化。然而,一般情况下情况要好得多,在一定数量的元素之后,大多数应该小于列表中的最后一个元素并且操作将是 O(log(k))
.
一种方法是使用最大大小为 k 的 min-heap (implemented as a binary tree)。查看一个新元素是否属于堆的时间复杂度为 O(1),因为它是一个最小堆,并且检索最小元素是一个常数时间操作。 O(n) 列表中的每个插入步骤(或非插入......在元素太小而无法插入的情况下)是 O(log k)。最后的树遍历和求和步骤是 O(k)。
总复杂度:
O (n log k + k) = O(n log k)
)
除非你的计算机上有多个内核运行,在这种情况下,并行计算是一种选择,求和应该只在最后进行。即时计算会增加额外的计算步骤,而实际上根本不会降低您的时间复杂度(您实际上会有更多的计算要做)。无论如何,您总是需要对 k 个元素求和,那么为什么不避免额外的加法和减法步骤呢?