求和组合码

时间:2015-02-21 07:20:53

标签: python combinatorics

您好我是Python新手,我正在尝试解决编码挑战,目标是创建一个函数,该函数采用整数数组(负数和正数)和目标值(也是整数)然后输出true如果数字的任何组合总和到目标值,它将始终大于输入数组中的任何其他单个元素。我试图这样做,但可怕的失败了。我发现其他人的代码是用2行代码完成的,但我不知道它是如何工作的,希望有人在这里指出我正确的方向。这是代码

def subsetsum(target, arr):
  if len(arr) == 0:
    return target == 0


  return subsetsum(target, arr[1:]) or subsetsum(target - arr[0], arr[1:])

我的意思是我甚至不知道他们在哪里总结数字并与目标进行比较,我们将非常感谢任何帮助。提前谢谢。

2 个答案:

答案 0 :(得分:0)

编辑该代码中存在错误(取决于您是否认为[1]中的数字组合总计为0)。尝试

subsetsum(0,[1])
> True

我在下面解释一下。 结束编辑

所以我认为理解代码的挑战不是关于Python,而是理解递归函数。

让我们假设函数subsetsum适用于长度小于N的列表。现在让我们取一些长度为N的列表。如果有一个子集与目标相加,则它涉及第一个元素({{ 1}})或者它没有。因此,我们将其分解为两个问题 - 检查是否存在具有第一个元素的子集,并检查是否存在不存在的子集。

请注意,arr[0]是一个长度为N-1的数组,以arr[1:]的第二个元素开头。

因此,如果有一个不涉及arr的子集,那么arr[0]将提供subsetsum(target,arr[1:])。如果有一个涉及True的子集,则arr[0]将返回subsetsum(target-arr[0],arr[1:])。如果两者都没有,那么它将返回True

所以基本上这是否适用于False取决于它是否适用于N,这取决于它是否适用于N-1等。最后我们得到长度为0.如果target为0,此时应返回N-2。如果没有,True,或者至少是编写此代码的人所想到的。我不同意。解释下面的错误。


就个人而言,我认为此代码中存在错误。如果我给它任何列表和0的目标,它将返回False测试应该是当它到达长度为1的列表时,目标是否等于那个值。测试应该是第一个元素是目标,如果它变为长度0列表,它失败了。

True

答案 1 :(得分:0)

他们的解决方案使用递归以非常聪明的方式表达所有可能的数字组合。但聪明并不总是意味着可读或易于理解(所有代码都应该是这样),所以不要立刻感觉不好。就个人而言,我会考虑这个好的代码。

最简单的思考方式是向后工作。

  • 如果arr有0个元素会怎样?好吧,它在函数的开头显式检查:如果target已经为0,它只能是问题的解决方案。让我们参考{{1}的这种特殊情况(subsetsum arr[]is_zero,因为它只是这样做。
  • 如果arr有1个元素[x]会怎样?要获得存在的解决方案,您必须通过在总和中包括或不包括target来获得x。这是通过将问题转换为0元素版本来完成的,因为arr[1:]将是空列表([])。 or表达式subsetsum(target, arr[1:])的第一部分忽略了x,并且基本上询问is_zero(target)。表达式的第二部分通过询问x在总和中包括is_zero(target - x)。试试arr = [9]。如果Trueis_zero(target),您将获得is_zero(target - 9)。这有道理,对吗?如果目标是0或9,则[0][9]分别是问题的解决方案。
  • 如果arr有2个元素[x, y]会怎样?同样,问题被缩减为1个元素更小的版本,因为arr[1:]只是[y]。那么,subsetsum(target, [y])中是否有解决方案?subsetsum(target - x, [y])中是否有解决方案。试试[3, 9]。如果True是9或0,则表达式的第一部分忽略3并评估target。第二部分包括3并且如果target - 3是9或0则评估为真(即{{1}是12或3)。因此,它尝试"所有可能的组合:target[][9][3]
  • [9, 3]缩减为subsetsum(target, [x, y, z])subsetsum(target, [y, z]),依此类推......

现在从上到下看,对于subsetsum(target - x, [y, z])中的每个元素,会发生什么问题,将问题分成两个子问题"如果不包括这个元素?"如果我们包含这个元素,那么"是否有解决方案?"这样,您最终会尝试所有arr组合。

使用Python的真正甜蜜的模块2**len(arr),这个问题的解决方案更加清晰(也更有效),但我现在没有时间编写它。不过,我明天可能只是为了好玩而尝试。

编辑:这是我更具可读性(也可能更快)的版本。

itertools

它只是找到所有子集,从长度0开始(所以import itertools def subsetsum(target, arr): for subset_len in range(len(arr) + 1): if any(sum(subset) == target for subset in itertools.combinations(arr, subset_len)): return True return False )并且长达[],并检查它们中的任何一个是否总和为len(arr)。 Python是一种美妙的语言!