确定列表中哪些数字是给定数字之和的算法

时间:2015-07-10 23:30:27

标签: algorithm

我有一个我试图解决的编码问题。我还没有能够提出一个好的算法。

给定数字X(例如200),确定列表中的哪些数字(例如:4,5,10,10,23,67,889,150,50)在求和时将等于X.在这种情况下答案是(50,150)。到目前为止,我考虑首先对列表进行排序(从最低到最高)然后循环添加数字,直到我得到大于X的值。丢弃列表中的所有剩余数字,因为它们不需要(例如889)。现在我有生成总和200所需的数字列表。现在我需要确定哪些数字总和为200.

目前陷入困境。

非常感谢任何想法。

3 个答案:

答案 0 :(得分:2)

这是一个背包问题。请参阅此处https://en.m.wikipedia.org/wiki/Knapsack_problem

答案 1 :(得分:0)

唯一可以丢弃的数字是大于目标数的数字,因为任何其他较小数字的组合可能总和达到所需数量。

要查找哪些(如果有),您必须检查剩余数字的所有可能组合。

最简单的方法是递归遍历列表,一旦添加当前数字,一旦将其删除,如果总和已经超过目标值,则修剪当前分支。

您的问题实例的示例(perl)实现在下面的代码段中给出:

my @numbers = (4, 5, 10, 10, 23, 67, 889, 150, 50);
my $length = scalar @numbers; # length of the list


sub visit {
  my ($i, $sum, $goal, $items) = @_;
  # i: current index, sum: sum of numbers currently selected
  # goal: goal value to reach, items: list of numbers currently selected 

  # we found a solution !
  print join (", ", @$items) . "\n" if $sum == $goal;

  return if $i >= $length || $sum >= $goal;

  # continue without adding
  visit ($i+1, $sum, $goal, $items);

  # continue with adding
  visit ($i+1, $sum + $numbers[$i], $goal, [$numbers[$i], @$items]);
}

visit (0, 0, 200, []);它会按预期报告50, 150对。

请注意,没有尝试删除重复项,因此,除了visit (0, 0, 77, []);三项50, 23, 4之外,目标值为77 67, 10的调用将被列出两次,因为有两个那里10的实例。

哦,不要相信其他帖子中提出的任何贪婪算法,因为它们注定无法解决背包问题。

答案 2 :(得分:0)

取决于。如果你想要它快,你可以使用贪婪(ish)算法:(伪代码)

n = answer; // what you want the numbers to add up to be. 
numbers = [1, 2, 40, 39,....]; //the candidates. 
addList = Array[][];
addList[0] = numbers;
level = 0;
while(true){
    for (number in numbers){
         currnum = addlist[level][i] + number;
         if(currnum == n){
             return true; // or what ever you want to return
         } else if (currnum < n){
              addlist[level+1].append(currnum);
         }
    }
    if (addlist[level+1].length ==0){
          return false; // it will never add up to the value n. 
    }
    level++;
}

这是严格的伪代码,我只是为了便于阅读而混合了arraylist和数组。