检查是否通过+和 - 元素的任意组合,数组总和为零

时间:2015-07-26 10:24:50

标签: python algorithm

The source of the question

这是一个面试问题,所以我认为它应该有一个解决方案,但我不确定它是什么,也找不到。

问题在于:

给定一个数字数组,检查是否可以在任何地方添加和减去,以使总和为零。

例如:

  

A = {2,1,8,5}

     

+ 2-1 + 8 + 5!= 0

     

-2-1 + 8 + 5!= 0

     

+ 2-1-8 + 5!= 0

     

-2-1 + 8-5 == 0

这样做了。

我已经有了指数解决方案的代码:

def isFeasible(A, p, _sum):
    if p == len(A):
        if _sum==0: return True
        else: return False;

    return (isFeasible(A, p+1, _sum+A[p]) or isFeasible(A, p+1, _sum-A[p]))


def driver(arr):
    print isFeasible(arr,0,0)

3 个答案:

答案 0 :(得分:1)

让我们为 i = 1..N 拨打 A [i] 号码。您需要解决以下等式:

  sum(X[i] * A[i]) = 0,   for X[i] = -1 or 1

显然,这相当于(只需在 X [] 中将-1更改为0):

  sum(X[i] * 2*A[i]) = sum(A[i]),   for X[i] = 0 or 1

第二个问题恰好是数字(A [i])partition problem,如果数字是任意的,则为NP-hard。此外,分区问题是众所周知的knapsack problem最简单的情况。只需阅读两本维基百科文章,您就会学到很多解决问题的方法。

编辑:另一个同等问题是:

  sum(X[i] * A[i]) = sum((1 - X[i]) * A[i])    for X[i] = 0 or 1

它与第二个等式相同,但现在可以清楚地看到这是一个分区问题: X [i] = 1 表示将元素放在左边, X [ i] = 0 表示将元素放在右边。放完所有元素后,总和必须相等。

另请注意,存在伪多项式解here,它也可以变为fully polynomial approximation scheme。还要注意背包问题可以通过meet-in-the-middle approach来解决,这可以减少从 O(2 ^ N) O(sqrt(2)^ N)的指数解的时间复杂度

结论:阅读有关这些问题的维基百科文章,您可以在那里找到所有信息。

答案 1 :(得分:0)

您可以使用memoization改进指数解决方案:如果您已经知道_sum的答案,请返回该答案。否则,计算并存储它。

但是,我想提出一个更有趣的解决方案。这是来自当地在线评委的类似问题的官方解决方案。在那个问题中,我们必须找到+/-到每个数字的实际分配,并保证存在解决方案。

解决方案是保留两组:添加一组数字和一组减去的数字。然后,我们会在找不到解决方案时随机执行以下操作:

if the current sum is smaller than the target:
  move a random element from the - set to the + set
else:
  move a random element from the + set to the - set

执行这些移动时,您可以更新O(1)中的当前总和。

这适用于在线评判的一秒钟内的50 000个数字。对于你的问题,你可以看到它是否在给定的时间约束下找到了解决方案,并假设没有一个解决方案,如果它没有。

我不知道这是一般的还是仅适用于特制的输入。也许其他人可以对此发表评论,但我总是惊讶于它在这个问题上的效果如何,这是官方的解决方案。

答案 2 :(得分:0)

如果我遗失了某些内容,请告诉我。

您可以轻松将此值降低为<?php echo(types_render_field( "bildeserie", array( 'raw' => true) )); ?> ,给定数组Subset Sum problem,值a查看是否存在总和为k的子集。< / p>

让我解释为什么这个问题与k相同。

说明数组中所有元素的总和为Subset sum problem。您要做的是:将X符号分配给总和为-且其余元素分配为x/2的元素子集,以便您的总和为零。

所以在你的问题中你想知道的是,如果有一个子集的总和恰好是+,如果有一个像这样的子数组那么分配X/2所有这些元素并自动总和总数组将为零。

现在您的解决方案是:

-

您可以编写一个简单的动态编程解决方案来找出这个:

     array - a
     sum of all elements -x
     return isSubsetSum(a,x/2)

抱歉,我不擅长python。只需将其转换为python自己。