找到在数组中求和的元素

时间:2011-04-18 11:50:11

标签: algorithm

给定一个元素数组(所有元素都是唯一的),给定一个总和 找到所有具有和s的子集。 对于前阵列{5,9,1,3,4,2,6,7,11,10} 总和是10 可能的子集是{10}, {6,4}, {7,3}, {5,3,2}, {6,3,1}等。 还有更多。 还可以找到这些子集的总数。 请帮我解决这个问题..

3 个答案:

答案 0 :(得分:2)

这是一个着名的回溯问题,可以通过递归来解决。基本上它是一种蛮力方法,其中尝试了每种可能的组合,但至少给出了3个边界条件来修剪搜索 这是算法:
到目前为止选择的元素总和的变量。
r变量用于剩余数组的总和。
M是所需的总和 k是以0开始的索引 w是给定整数的数组

Sum(k,s,r)
{
    x[k]:=1;  //select the current element
    if(s<=M & r>=M-s & w[k]<=M-s)
    then
    {
        if(s+w[k]==M)
        then output all i [1..k] that x[i]=1
        else
        sum(k+1,s+w[k],r-w[k])
    }
    x[k]:=0  //don't select the current element
    if(s<=M) & (r>=M-s) & (w[k]<=M-s)
    then
    {
        if (M==s)
        then output all i [1..k] that x[i]=1
        else
        sum(k+1,s,r-w[k])
    }
}

我使用数组“x”来标记为解决方案选择的候选数字。在每个步骤3检查边界条件:

1. Sum of selected elements in "x" from "w" shouldn't exceed M. s<M.    
2. Remaining numbers in array should be able to complete M. r>=M-s.
3. Single remaining value in w shouldn't overflow M. w[k]<=M-s.  

如果任何条件失败,该分支将被终止。

答案 1 :(得分:1)

这里有一些python代码正在做你想要的。它广泛使用了itertools以便了解它你可能想看看itertools docs

>>> import itertools
>>> vals = (5,9,1,3,4,2,6,7,11,10)
>>> combos = itertools.chain(*((x for x in itertools.combinations(vals, i) if sum(x) == 10) for i in xrange(len(vals)+1)))
>>> for c in combos: print c
...
(10,)
(9, 1)
(3, 7)
(4, 6)
(5, 1, 4)
(5, 3, 2)
(1, 3, 6)
(1, 2, 7)
(1, 3, 4, 2)

它的作用基本上是这样的:

  • 对于所有可能的子集大小 - for i in xrange(len(vals)+1),请执行:
  • 对具有此大小的所有子集进行迭代 - for x in itertools.combinations(vals, i)
  • 测试子集值的总和是否为10 - if sum(x) == 10
  • 在这种情况下,产生子集

对于每个子集大小,产生另一个生成器,因此我使用itertools.chain将它们链接在一起,因此有一个生成器产生所有解决方案。

由于你只有一个生成器而不是一个列表,你需要在迭代它时对元素进行计数 - 或者你可以使用list(combos)将生成器中的所有值放入一个列表中(这会消耗生成器,所以不要在之前/之后尝试迭代它。)

答案 2 :(得分:0)

既然你没有说它是否是家庭作业,我只给出一些提示:

  • nums成为您可以使用的数字数组(在您的示例中为nums = {5,9,1,3,4,2,6,7,11,10}

  • targetSum为您给出的总和值(在您的示例中为targetSum = 10

  • 排序nums:您不希望使用nums

  • 中较大的targetSum元素搜索解决方案
  • S_s为一组取自nums的整数,其总和等于s

  • R_s成为所有S_s

  • 的集合
  • 您想查找R_s(在您的示例中为R_10

  • 现在,假设您有一个函数find(i, s),它使用从R_s开始的nums的子数组返回i

    • 如果您nums[i] > s可以停止(请记住您之前已排序nums

    • 如果找到nums[i] == s R_s = { { nums[i] } },请将其退回

    • 对于您要计算j in [1 .. nums.length - 1]的每个R_s' = find(i + j, targetSum - nums[i]),然后将nums[i]添加到R_s'中的每个集合,并将其添加到您的结果R_s }

  • 通过实施find并致电find(0, 10)

  • 来解决您的问题

我希望这会有所帮助