找到所需元素的最小数量,使其总和等于或超过S.

时间:2011-05-11 12:11:28

标签: arrays algorithm subset-sum

我知道这可以通过对数组进行排序并获取更大的数字直到满足所需条件来完成。这至少需要nlog(n)的排序时间。

nlog(n)有什么改进吗?

我们可以假设所有数字都是正数。

5 个答案:

答案 0 :(得分:9)

这是一个O(n + size(smallest subset) * log(n))的算法。如果最小的子集比数组小得多,则为O(n)

如果我对算法的描述不清楚,请阅读http://en.wikipedia.org/wiki/Heap_%28data_structure%29(详细信息,但细节都在那里)。

  1. 将数组转换为堆,使得最大元素及时可用O(n)
  2. 反复从堆中提取最大元素,直到它们的总和足够大。这需要O(size(smallest subset) * log(n))
  3. 这几乎可以肯定是他们希望得到的答案,但不应该让它不应该是一个交易破坏者。

    编辑:这是另一种变体,它通常更快,但可能更慢。

    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时。

答案 1 :(得分:7)

假设数字是整数,你可以改进排序的通常n lg(n)复杂度,因为在这种情况下,我们有额外的信息,值在0和S之间(对于我们的目的,大于S的整数是与S)相同。

由于值的范围是有限的,您可以使用非比较排序算法(例如Pigeonhole SortRadix Sort)低于n lg(n)

请注意,这些方法取决于S的某些函数,因此如果S变得足够大(并且n保持足够小),那么最好还原为比较排序。

答案 2 :(得分:5)

对Theta(nlogn)的一个改进(渐近)你可以做的是得到一个O(n log K)时间算法,其中K是所需的最小元素数。

因此,如果K是常数,或者说log n,这比排序更好(渐近)。当然如果K是n ^ epsilon,那么这并不比Theta(n logn)好。

这样做的方法是使用selection algorithms,它可以告诉你O(n)时间内i th 最大元素。

现在进行二元搜索K,从i = 1(最大)开始,每回合加倍i等。

你发现i th 最大,找到i个最大元素的总和并检查它是否大于S.

这样,您可以运行选择算法的O(log K)运行(O(n)),总运行时间为O(n log K)。

答案 3 :(得分:5)

这是问题的O(n)预期时间解决方案。这有点像Moron的想法,但我们并没有抛弃我们的选择算法在每一步中所做的工作,我们开始尝试从中间的项目而不是使用重复的加倍方法。

或者,它实际上只是quickselect,还有一点额外的预订余额。

首先,很明显,如果您按排序顺序排列元素,则可以先选择最大的项目,直到超过所需的总和。我们的解决方案就是这样,除非我们尽可能地努力不发现订购信息,因为排序很慢。

您希望能够确定给定值是否为截止值。如果我们包含该值以及大于它的所有值,我们会达到或超过S,但是当我们删除它时,那么我们低于S,那么我们就是金色。

这是伪代码,我没有对边缘情况进行测试,但这可以解决这个问题。

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)  

答案 4 :(得分:0)

  1. 消除数字&lt; S,如果你找到一些数字== S,那么就解决了
  2. pigeon-hole对数字进行排序&lt;小号
  3. 在排序顺序中将元素从最高到最低求和,直到超过S.