【问题标题】:how can i reduce the time complexity of subset sum problem如何降低子集和问题的时间复杂度
【发布时间】:2020-09-22 12:35:10
【问题描述】:

所以最近我一直在尝试解决一些有趣的问题,但一直卡在这个问题上。

给定一组对象 1 到 N。n1 个值为 0 的对象和 n2 个值为 1 的对象和 n3 个值为 2 的对象。 需要计算总和为 3 或其倍数的所有子集。

n1+ n2 + n3 = N

我已经能够解决这个问题,但无法降低这个问题的时间复杂度。 我的解决方案仍然具有指数时间复杂度。我正在尝试降低时间复杂度,以便我可以在 5 秒内运行 N = 100,000 的大型集合。

这是我偶然发现的另一个简单但直观的解决方案,但时间复杂度又是问题所在。

def mask(lst, m):
    # pad number to create a valid selection mask
    # according to definition in the solution laid out
    m = m.zfill(len(lst))
    return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))

def subset_sum(lst, target):
    # there are 2^n binary numbers with length of the original list
    for i in range(2**len(last)):
        # create the pick corresponsing to current number
        pick = mask(lst, bin(i)[2:])
        if sum(pick) == target:
            yield pick

我不需要确切的编码解决方案,但如果你能指出我正确的方向并且任何编程语言都可以,我想知道解决方案的逻辑/方法。

【问题讨论】:

  • 这里C++的工作是什么?
  • 仅仅因为您对几种编程语言持开放态度并不是标记所有这些语言的理由。仅标记您的 sn-p 代码的语言
  • 虽然可以是很多子集。您需要计算它们还是列出它们?
  • 我的意思是可能有指数级的子集适合,所以如果你列出它们,你永远无法达到 100 000(或 1 000)。
  • @ChristianSloper 我只需要数一数。

标签: python python-3.x algorithm subset-sum


【解决方案1】:

看起来,给定一个数字数组(全部为 0、1 或 2),您希望返回这些数字的每个子集,总和为 3 的倍数,并且您希望以多项式方式进行。

这是不可能的。

要查看这一点,请考虑数组 [2,1,0,0,0,0,0,...,0]。为了得到 3 的总和,我们将始终需要前两个数字,但除此之外,任何子集的总和为 3。因为我们有 N-2 0,这给出了符合要求的 2**(N-2) 子集的总数。无法在多项式时间内返回指数数量的答案。

【讨论】:

  • 多项式或至少伪多项式。我知道这似乎很难在上述时间内实现,但这很糟糕,存在解决方案,我正在努力寻找或至少接近它。
  • @ADdV 如果他只想计算子集的数量,那么多项式复杂度是可能的
【解决方案2】:

所以这里的一个关键知识是和必须是 3 的倍数,即 sum = 0 (mod 3)。

这意味着您可以在任何子集中包含任意数量的 n1,因为它们不会改变总和。

因此,您可以立即将问题简化为从 n2 和 n3 中找到总和为 0(mod 3)的子集,然后将所有可能的 2**n1 子集添加到这些子集中。请注意,对于 n1 的任何显着值(例如 50 以上),列出它们变得无法计算。

但是很容易计算:

那么如何从 n2 和 n3 中找到 sum = 0 (mod 3) 的集合。我们知道 n2 中的任何元素都会将和加一,给定 n2 中的 m 个元素,我们可以计算出可能有多少个元素

所以是一个松散的计数伪代码:

def f(n1,n2,n3):
    for i in range(0,n2+1):
        # i elements of n2
        # compute i%3
        # if i%3 0 then we can pick j = 0,3,6,9 ... elements from n3
        # if i%3 1 then we can pick j = 1,4,7,10 .. elements from n3
        # if i#3 2 then we cannot j = 2, 5, 8, 11 .. elements from n3
        # compute the combination c = (n choose i) * (n choose j) for each j
        # for each c multiply by 2**n1 (adding on all possible subsets from n1)

【讨论】:

  • 嘿,谢谢,有趣的方法,我要试一试。
  • 是的,我只需要数一数,不需要列出
  • 好吧,这个解决方案可行,但问题仍然在于时间复杂度,因为在 for 循环的每一步计算如此多的二项式系数以获取更大的 n3 会导致时间复杂度爆炸式增长。
  • 所以现在的问题是如何减少这个计算
猜你喜欢
  • 1970-01-01
  • 2022-06-28
  • 2012-07-28
  • 2011-06-15
  • 2016-01-08
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多