你如何从给定的N个数字中测试所有可能的加法组合,使它们加起来得到给定的最终数字?

一个简单的例子:

要添加的数字集:N ={1,5,22,15,0,…} 期望结果:12345


当前回答

Perl版本(前导答案):

use strict;

sub subset_sum {
  my ($numbers, $target, $result, $sum) = @_;

  print 'sum('.join(',', @$result).") = $target\n" if $sum == $target;
  return if $sum >= $target;

  subset_sum([@$numbers[$_ + 1 .. $#$numbers]], $target, 
             [@{$result||[]}, $numbers->[$_]], $sum + $numbers->[$_])
    for (0 .. $#$numbers);
}

subset_sum([3,9,8,4,5,7,10,6], 15);

结果:

sum(3,8,4) = 15
sum(3,5,7) = 15
sum(9,6) = 15
sum(8,7) = 15
sum(4,5,6) = 15
sum(5,10) = 15

Javascript版本:

const subsetSum = (numbers, target, partial = [], sum = 0) => { If (sum < target) 数字。forEach((num, i) => subsetSum(数字。Slice (i + 1), target, partial.concat([num]), sum + num)); Else if (sum == target) console.log(的总和(% s) = % s, partial.join(),目标); } subsetSum([3、9、8、4、5、7、10、6],15);

Javascript一行实际返回结果(而不是打印它):

const subsetSum = (n, t, p = [], s = 0, r = []) = > (s < t ? n.forEach ((l i) = > subsetSum (n.slice (i + 1), t,[……p、l], s + l r)): s = = t ? r.push (p): 0, r); console.log (subsetSum([3、9、8、4、5、7、10、6],15));

我最喜欢的是带有回调的一行语句:

const subsetSum = (n, t,辛西娅·布雷齐尔,p =黑铝,s = 0) = > s & lt; t ? n.forEach ((l, i) = > subsetSum (n.slice (i + 1)、t、辛西娅·布雷齐尔,黑... p, l铝,s + l)): s = = t ?辛西娅·布雷齐尔(p): 0; 子集([3,9,8,4,5,7,10,6],15,console.log);

其他回答

我想我应该用这个问题的答案,但我不能,所以这是我的答案。它使用的是《计算机程序的结构和解释》中答案的修改版本。我认为这是一个更好的递归解,应该更能取悦纯粹主义者。

我的答案是用Scala(如果我的Scala很烂,我很抱歉,我刚刚开始学习)。findsumcombination的疯狂之处在于对递归的原始列表进行排序和惟一,以防止欺骗。

def findSumCombinations(target: Int, numbers: List[Int]): Int = {
  cc(target, numbers.distinct.sortWith(_ < _), List())
}

def cc(target: Int, numbers: List[Int], solution: List[Int]): Int = {
  if (target == 0) {println(solution); 1 }
  else if (target < 0 || numbers.length == 0) 0
  else 
    cc(target, numbers.tail, solution) 
    + cc(target - numbers.head, numbers, numbers.head :: solution)
}

使用它:

 > findSumCombinations(12345, List(1,5,22,15,0,..))
 * Prints a whole heap of lists that will sum to the target *

用excel找到组合(相当容易)。 (你的电脑不能太慢)

去这个网站 进入“Sum to Target”页面 下载“Sum to Target”excel文件。 按照网站页面上的说明操作。

希望这能有所帮助。

import java.util.*;

public class Main{

     int recursionDepth = 0;
     private int[][] memo;

     public static void main(String []args){
         int[] nums = new int[] {5,2,4,3,1};
         int N = nums.length;
         Main main =  new Main();
         main.memo = new int[N+1][N+1];
         main._findCombo(0, N-1,nums, 8, 0, new LinkedList() );
         System.out.println(main.recursionDepth);
     }


       private void _findCombo(
           int from,
           int to,
           int[] nums,
           int targetSum,
           int currentSum,
           LinkedList<Integer> list){

            if(memo[from][to] != 0) {
                currentSum = currentSum + memo[from][to];
            }

            if(currentSum > targetSum) {
                return;
            }

            if(currentSum ==  targetSum) {
                System.out.println("Found - " +list);
                return;
            }

            recursionDepth++;

           for(int i= from ; i <= to; i++){
               list.add(nums[i]);
               memo[from][i] = currentSum + nums[i];
               _findCombo(i+1, to,nums, targetSum, memo[from][i], list);
                list.removeLast();
           }

     }
}

Perl版本(前导答案):

use strict;

sub subset_sum {
  my ($numbers, $target, $result, $sum) = @_;

  print 'sum('.join(',', @$result).") = $target\n" if $sum == $target;
  return if $sum >= $target;

  subset_sum([@$numbers[$_ + 1 .. $#$numbers]], $target, 
             [@{$result||[]}, $numbers->[$_]], $sum + $numbers->[$_])
    for (0 .. $#$numbers);
}

subset_sum([3,9,8,4,5,7,10,6], 15);

结果:

sum(3,8,4) = 15
sum(3,5,7) = 15
sum(9,6) = 15
sum(8,7) = 15
sum(4,5,6) = 15
sum(5,10) = 15

Javascript版本:

const subsetSum = (numbers, target, partial = [], sum = 0) => { If (sum < target) 数字。forEach((num, i) => subsetSum(数字。Slice (i + 1), target, partial.concat([num]), sum + num)); Else if (sum == target) console.log(的总和(% s) = % s, partial.join(),目标); } subsetSum([3、9、8、4、5、7、10、6],15);

Javascript一行实际返回结果(而不是打印它):

const subsetSum = (n, t, p = [], s = 0, r = []) = > (s < t ? n.forEach ((l i) = > subsetSum (n.slice (i + 1), t,[……p、l], s + l r)): s = = t ? r.push (p): 0, r); console.log (subsetSum([3、9、8、4、5、7、10、6],15));

我最喜欢的是带有回调的一行语句:

const subsetSum = (n, t,辛西娅·布雷齐尔,p =黑铝,s = 0) = > s & lt; t ? n.forEach ((l, i) = > subsetSum (n.slice (i + 1)、t、辛西娅·布雷齐尔,黑... p, l铝,s + l)): s = = t ?辛西娅·布雷齐尔(p): 0; 子集([3,9,8,4,5,7,10,6],15,console.log);

Thank you.. ephemient

我已经将上述逻辑从python转换为php..

<?php
$data = array(array(2,3,5,10,15),array(4,6,23,15,12),array(23,34,12,1,5));
$maxsum = 25;

print_r(bestsum($data,$maxsum));  //function call

function bestsum($data,$maxsum)
{
$res = array_fill(0, $maxsum + 1, '0');
$res[0] = array();              //base case
foreach($data as $group)
{
 $new_res = $res;               //copy res

  foreach($group as $ele)
  {
    for($i=0;$i<($maxsum-$ele+1);$i++)
    {   
        if($res[$i] != 0)
        {
            $ele_index = $i+$ele;
            $new_res[$ele_index] = $res[$i];
            $new_res[$ele_index][] = $ele;
        }
    }
  }

  $res = $new_res;
}

 for($i=$maxsum;$i>0;$i--)
  {
    if($res[$i]!=0)
    {
        return $res[$i];
        break;
    }
  }
return array();
}
?>