这是一个面试问题,所以我认为它应该有一个解决方案,但我不确定它是什么,也找不到。
问题在于:
给定一个数字数组,检查是否可以在任何地方添加和减去,以使总和为零。
例如:
这样做了。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)
答案 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自己。