【问题标题】:Algorithm to determine which numbers in a list are the sum of a given number确定列表中哪些数字是给定数字之和的算法
【发布时间】:2015-07-10 23:30:27
【问题描述】:

我有一个正在尝试解决的编码问题。我还没有想出一个好的算法。

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

目前卡在这一点上。

非常感谢任何想法。

【问题讨论】:

  • 我认为你不能在达到总数后丢弃数字:如果它们的组合不起作用怎么办?我认为您必须继续使用小于所需总数的所有数字。并且可能从那里从最高到最低工作。
  • 有一个非常著名的动态规划算法来解决这个问题。它被称为子集和。
  • 您想统计总和等于X 的子集的数量,或者您想查找是否有一个子集是`X`?

标签: algorithm


【解决方案1】:

这是一个背包问题。参考这里https://en.m.wikipedia.org/wiki/Knapsack_problem

【讨论】:

  • 其实是子集和问题。
  • 只有在没有负数的时候才是背包。
【解决方案2】:

视情况而定。如果你想要它快,你可以使用贪心(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 和 array 混合在一起只是为了便于阅读。

【讨论】:

    【解决方案3】:

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

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

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

    您的问题实例的示例 (perl) 实现在下面的 sn-p 中给出:

    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 对。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-27
      • 2012-11-17
      • 2015-10-31
      • 1970-01-01
      • 1970-01-01
      • 2016-10-20
      • 2023-01-07
      • 2011-06-09
      相关资源
      最近更新 更多