Arrays 找到所需的最小元素数,使其总和等于或超过S
我知道这可以通过对数组排序并获取较大的数字来实现,直到满足所需的条件。这至少需要nlog(n)排序时间 与nlog(n)相比,是否有任何改进Arrays 找到所需的最小元素数,使其总和等于或超过S,arrays,algorithm,subset-sum,Arrays,Algorithm,Subset Sum,我知道这可以通过对数组排序并获取较大的数字来实现,直到满足所需的条件。这至少需要nlog(n)排序时间 与nlog(n)相比,是否有任何改进 我们可以假设所有的数字都是正的。假设这些数字是整数,您可以改进通常的n lg(n)排序的复杂性,因为在这种情况下,我们有额外的信息,即值在0到S之间(为了我们的目的,大于S的整数与S相同) 由于值的范围是有限的,因此可以使用非比较排序算法,例如或,使其低于nlg(n) 请注意,这些方法依赖于S的某些函数,因此如果S变得足够大(而n保持足够小),则最好恢复到
我们可以假设所有的数字都是正的。假设这些数字是整数,您可以改进通常的
n lg(n)
排序的复杂性,因为在这种情况下,我们有额外的信息,即值在0到S之间(为了我们的目的,大于S的整数与S相同)
由于值的范围是有限的,因此可以使用非比较排序算法,例如或,使其低于nlg(n)
请注意,这些方法依赖于S的某些函数,因此如果S变得足够大(而n保持足够小),则最好恢复到比较排序。相对于θ(nlogn),您可以做的一个改进(渐近)是获得O(n log K)时间算法,其中K是所需的最小元素数
因此,如果K是常数,或者说logn,这比排序更好(渐进)。当然,如果K是n^epsilon,那么这并不比θ(nlogn)好
方法是使用,它可以告诉你O(n)时间内第i个最大的元素
现在对K进行二元搜索,从i=1(最大值)开始,在每一个回合加倍i等
找到第i个最大元素,找到i个最大元素的和,然后检查它是否大于S
这样,您将运行选择算法的O(log K)次运行(即O(n)),总运行时间为O(n log K)。这里有一个算法是
O(n+大小(最小子集)*log(n))
。如果最小的子集比数组小得多,这将是O(n)
如果我对算法的描述不清楚,请阅读(细节很清楚,但细节都在那里)
O(n)
中可用O(大小(最小子集)*log(n))
Walk through elements, until the sum of the first few exceeds S. Store current_sum.
Copy those elements into an array.
Heapify that array such that the minimum is easy to find, remember the minimum.
For each remaining element in the main array:
if min(in our heap) < element:
insert element into heap
increase current_sum by element
while S + min(in our heap) < current_sum:
current_sum -= min(in our heap)
remove min from heap
遍历元素,直到前几个元素的总和超过S。存储当前元素的总和。
将这些元素复制到数组中。
将数组重设为易于找到的最小值,记住最小值。
对于主阵列中的每个剩余元素:
如果min(在我们的堆中)<元素:
将元素插入堆中
按元素增加当前_和
而S+min(在我们的堆中)<当前的总和:
当前_sum-=min(在我们的堆中)
从堆中删除最小值
如果我们能够在不操纵堆的情况下拒绝大部分数组,这可能是以前解决方案的两倍。但是它也可能较慢,例如当数组中的最后一个元素恰好大于S时。这里是一个O(n)预期时间问题的解决方案。这有点像白痴的想法,但我们不会抛出我们的选择算法在每一步中所做的工作,我们开始尝试从一个潜在的中间项目,而不是使用重复加倍方法。
或者,它实际上只是为剩余的金额增加一点簿记
首先,很明显,如果元素按排序顺序排列,可以先选择最大的项,直到超过所需的总和。我们的解决方案将是这样的,只是我们将尽可能不发现排序信息,因为排序很慢
您希望能够确定给定值是否为截止值。如果我们把这个值和所有大于它的东西都包括在内,我们会达到或超过S,但当我们去掉它时,我们就低于S,我们就是黄金
这是psuedo代码,我没有测试它的边缘情况,但这让人明白了这个想法
def Solve(arr, s):
# We could get rid of worse case O(n^2) behavior that basically never happens
# by selecting the median here deterministically, but in practice, the constant
# factor on the algorithm will be much worse.
p = random_element(arr)
left_arr, right_arr = partition(arr, p)
# assume p is in neither left_arr nor right_arr
right_sum = sum(right_arr)
if right_sum + p >= s:
if right_sum < s:
# solved it, p forms the cut off
return len(right_arr) + 1
# took too much, at least we eliminated left_arr and p
return Solve(right_arr, s)
else:
# didn't take enough yet, include all elements from and eliminate right_arr and p
return len(right_arr) + 1 + Solve(left_arr, s - right_sum - p)
def解算(arr,s):
#我们可以消除基本上从未发生过的更糟糕的O(n^2)行为
#通过在这里决定性地选择中值,但在实践中,常数
#影响算法的因素会更糟。
p=随机元素(arr)
左,右=分区(arr,p)
#假设p既不在左对齐,也不在右对齐
右和=和(右和)
如果右和+p>=s:
如果右和
按排序顺序将元素从高到低求和,直到超过S。@equality:是的,我更正了我的帖子。O(n log(n))算法是否不足以让他们相信你是一个好的候选人?对我来说,这听起来是一个不错的解决方案。@equality:S不一定是常数,它只需要知道。如果它是常数或有界的,则可以通过提前分配存储桶来提高现实世界的性能,但这对算法的理论复杂性没有影响。@等式:当我说“已知”时,我的意思是“在任何计算之前已知”。比较排序有一个硬限制的原因是,您事先不知道值在什么范围内,有多少个值,等等。预先知道一些信息是允许非比较排序在某些情况下执行得更好的原因。我认为我的解决方案应该被接受。它会给你一个最佳的答案,而不必使用ne