如果有n
未排序的权重,我需要找到最少数量的权重才能获得至少权重W
。
如何在O(n)
中找到它们?
答案 0 :(得分:3)
此问题有许多解决方法:
方法1 - 排序 - O(nlogn)
我想最简单的一个是按降序排序,然后取第一个K元素,它们总和至少为W.时间复杂度虽然是O(nlogn)
。
方法2 - 最大堆 - O(n + klogn)
另一种方法是使用最大堆。
创建堆将采用O(n)
然后提取元素,直到我们达到至少为W的总和。每次提取将花费O(logn)
,因此总时间复杂度为O(klogn)
其中k
1}}是我们必须从堆中提取的元素数。
方法3 - 使用Min Heap - O(nlogk)
添加JimMischel在以下评论中建议的此方法
创建一个最小堆,其中列表中的第一个k
元素总和至少为W
。然后,迭代剩余的元素,如果它大于它们之间的最小值(堆顶部)替换
在这一点上,我们可能需要更多的元素来实现W
,所以我们只需要提取最小值,直到达到极限。在实践中,取决于
find_min_set(A,W)
currentW = 0
heap H //Create empty heap
for each Elem in A
if (currentW < W)
H.add(Elem)
currentW += Elem
else if (Elem > H.top())
currentW += (Elem-H.top())
H.pop()
H.add(Elem)
while (currentW-H.top() > W)
currentW -= H.top()
H.pop()
此方法在实践中可能更快,具体取决于k
和n
之间的关系。请参阅when theory meets practice。
方法4 - O(n)
我能想到的最好的方法是使用某种quickselect,同时跟踪总重量,并始终将中位数作为支点进行划分。
首先,让我们定义一些事情:
sum(A)
- 数组A
中所有元素的总和。
num(A)
- 数组A
中的元素数量
med(A)
- 数组A
的中位数。
find_min_set(A,W,T)
//partition A
//L contains all the elements of A that are less than med(A)
//R contains all the elements of A that are greater or equal to med(A)
L, R = partition(A,med(A))
if (sum(R)==W)
return T+num(R)
if (sum(R) > W)
return find_min_set(R,W,T)
if (sum(R) < W)
return find_min_set(L,W-sum(R),num(R)+T)
通过find_min_set(A,W,0)
调用此方法。
运行时复杂性:
O(n)
。O(n)
。T(n) = T(n/2) + O(n)
,与quickselect = O(n)
的平均情况相同。 注意:当所有值都是唯一的时,最坏情况和平均复杂度确实都是O(n)
。对于可能的重复值,平均复杂度仍为O(n)
,但最糟糕的情况是O(nlogn)
,使用Median of medians方法选择数据透视。