【问题标题】:Find combination(s) sum of element(s) in array whose sum equal to a given number [duplicate]在数组中查找总和等于给定数字的元素的组合总和[重复]
【发布时间】:2012-10-11 10:24:59
【问题描述】:

可能重复:
Algorithm: Extract subset based on property sum

在简单的情况下,我们有一个数组:

{6, 1, 3, 11, 2, 5,12}

我们想知道该数组中包含的元素总和的所有组合以得到 12

在这种情况下,我们将得到四种组合:

  • 12
  • 1 + 11
  • 6 + 5 + 1
  • 1 + 3 + 2 + 6

那么,我们如何在 BASIC 或 PHP 中做到这一点?也许首先是伪代码;-)。

我一直在寻找,但只是找到了一个包含预定数量元素的组合。

【问题讨论】:

  • 是的,请先伪代码。
  • N=2^set_size;对于 (i=0;i target_sum)

标签: php algorithm


【解决方案1】:

你可以试试

echo "<pre>";

$sum = 12 ; //SUM
$array = array(6,1,3,11,2,5,12);
$list = array();

# Extract All Unique Conbinations
extractList($array, $list);

#Filter By SUM = $sum
$list = array_filter($list,function($var) use ($sum) { return(array_sum($var) == $sum);});

#Return Output
var_dump($list);

输出

array
  0 => 
    array
      1 => string '1' (length=1)
      2 => string '2' (length=1)
      3 => string '3' (length=1)
      4 => string '6' (length=1)
  1 => 
    array
      1 => string '1' (length=1)
      2 => string '5' (length=1)
      3 => string '6' (length=1)
  2 => 
    array
      1 => string '1' (length=1)
      2 => string '11' (length=2)
  3 => 
    array
      1 => string '12' (length=2)

使用的功能

function extractList($array, &$list, $temp = array()) {
    if (count($temp) > 0 && ! in_array($temp, $list))
        $list[] = $temp;
    for($i = 0; $i < sizeof($array); $i ++) {
        $copy = $array;
        $elem = array_splice($copy, $i, 1);
        if (sizeof($copy) > 0) {
            $add = array_merge($temp, array($elem[0]));
            sort($add);
            extractList($copy, $list, $add);
        } else {
            $add = array_merge($temp, array($elem[0]));
            sort($add);
            if (! in_array($temp, $list)) {
                $list[] = $add;
            }
        }
    }
}

【讨论】:

  • 不想冒犯你,但这段代码丑得可怕......
  • @Karoly Horvath 我相信你可以把它清理干净..... :)
  • 刚刚好!它似乎也比我发现的任何其他解决方案更短更容易!谢谢:)
【解决方案2】:

问题是NP-Hard。即使确定问题的任何子集是否总和为所需数字也是 NP-Hard(称为subset sum problem),并且没有已知的多项式解决方案。

因此,您应该寻找指数解决方案,例如回溯解决方案 - 生成所有可能的组合,并检查它们是否有效。

您可以使用修剪来加快搜索速度(例如,如果您生成 sum 13 的部分子集,则无需检查作为该子集超集的其他子集,因为它们肯定不会导致解决方案.

伪代码:

findValidSubsets(sum,arr,idx,currSolution):
   if (sum == 0):
       print currSolution
   if (sum < 0): //trim the search, it won't be succesful
       return
   //one possibility: don't take the current candidate
   findPermutations(sum,arr,idx+1,currSolution) 

   //second poassibility: take the current candidate
   currSolution.add(arr[idx])
   findPermutations(sum-arr[idx],arr,idx+1,currSolution)

   //clean up before returning: 
   currSolution.removeLast()

复杂度为O(2^n) - 需要在最坏的情况下生成所有 2^n 个可能的子集
使用findValidSubsets(desiredSum,myArray,0,[]) 调用,其中[] 是一个空的初始列表

【讨论】:

  • 修剪仅在没有负数的情况下有效。如果有,请先排序,然后您可以使用(更通用的)修剪。
  • 感谢@KarolyHorvath 的评论 - 仅对正面的澄清和改进建议。致 Bakti 和未来的读者:为避免修剪,只需删除 if(sum&lt;0) return 部分。
【解决方案3】:

使用动态规划,您可以将解决方案表示为

solver(sum,start_index)
     stop_condition_here_when sum <= 0

     r=0
     for  i=start_index ; i < last_iddex :
            r += solver(sum - array[i],i+1)
            r += solver(sum ,i+1)
     return r

添加额外的备忘录也会加速这个程序

【讨论】:

    【解决方案4】:

    您可以迭代集合的长度。在每一步中,检查所有长度为k的子集:

    for k = 1 to size(input):
        foreach permutation p of length k:
            if sum(p) == 12:
                bam!
    

    【讨论】:

    • 请注意,您不需要遍历所有 permutations 每个 k 有 k!,您需要遍历所有子集,只有 ' '2^n 的那些。
    • 更正:每个k 都有Choose(n,k)*k! = n!/(n-k)! 可能的排列。
    猜你喜欢
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2012-12-27
    相关资源
    最近更新 更多