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

一个简单的例子:

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


当前回答

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();
}
?>

其他回答

function solve(n){
    let DP = [];

     DP[0] = DP[1] = DP[2] = 1;
     DP[3] = 2;

    for (let i = 4; i <= n; i++) {
      DP[i] = DP[i-1] + DP[i-3] + DP[i-4];
    }
    return DP[n]
}

console.log(solve(5))

这是JS的一个动态解决方案,告诉任何人有多少种方法可以得到一定的总和。如果考虑到时间和空间的复杂性,这可能是正确的解决方案。

PHP版本,灵感来自Keith Beller的c#版本。

bala的PHP版本不适合我,因为我不需要对数字进行分组。我想要一个更简单的实现,只有一个目标值和一个数字池。这个函数也会删除任何重复的条目。

编辑25/10/2021:添加精度参数以支持浮点数(现在需要bcmath扩展)。

/**
 * Calculates a subset sum: finds out which combinations of numbers
 * from the numbers array can be added together to come to the target
 * number.
 *
 * Returns an indexed array with arrays of number combinations.
 *
 * Example:
 *
 * <pre>
 * $matches = subset_sum(array(5,10,7,3,20), 25);
 * </pre>
 *
 * Returns:
 *
 * <pre>
 * Array
 * (
 *   [0] => Array
 *   (
 *       [0] => 3
 *       [1] => 5
 *       [2] => 7
 *       [3] => 10
 *   )
 *   [1] => Array
 *   (
 *       [0] => 5
 *       [1] => 20
 *   )
 * )
 * </pre>
 *
 * @param number[] $numbers
 * @param number $target
 * @param array $part
 * @param int $precision
 * @return array[number[]]
 */
function subset_sum($numbers, $target, $precision=0, $part=null)
{
    // we assume that an empty $part variable means this
    // is the top level call.
    $toplevel = false;
    if($part === null) {
        $toplevel = true;
        $part = array();
    }

    $s = 0;
    foreach($part as $x)
    {
        $s = $s + $x;
    }

    // we have found a match!
    if(bccomp((string) $s, (string) $target, $precision) === 0)
    {
        sort($part); // ensure the numbers are always sorted
        return array(implode('|', $part));
    }

    // gone too far, break off
    if($s >= $target)
    {
        return null;
    }

    $matches = array();
    $totalNumbers = count($numbers);

    for($i=0; $i < $totalNumbers; $i++)
    {
        $remaining = array();
        $n = $numbers[$i];

        for($j = $i+1; $j < $totalNumbers; $j++)
        {
            $remaining[] = $numbers[$j];
        }

        $part_rec = $part;
        $part_rec[] = $n;

        $result = subset_sum($remaining, $target, $precision, $part_rec);
        if($result)
        {
            $matches = array_merge($matches, $result);
        }
    }

    if(!$toplevel)
    {
        return $matches;
    }

    // this is the top level function call: we have to
    // prepare the final result value by stripping any
    // duplicate results.
    $matches = array_unique($matches);
    $result = array();
    foreach($matches as $entry)
    {
        $result[] = explode('|', $entry);
    }

    return $result;
}

例子:

$result = subset_sum(array(5, 10, 7, 3, 20), 25);

这将返回一个包含两个数字组合数组的索引数组:

3, 5, 7, 10
5, 20

浮点数示例:

// Specify the precision in the third argument
$result = subset_sum(array(0.40, 0.03, 0.05), 0.45, 2);

这将返回一个匹配项:

0.40, 0.05

这个问题的一个迭代c++堆栈解决方案。与其他迭代解决方案不同的是,它不会对中间序列进行不必要的复制。

#include <vector>
#include <iostream>

// Given a positive integer, return all possible combinations of
// positive integers that sum up to it.

std::vector<std::vector<int>> print_all_sum(int target){
    std::vector<std::vector<int>> output;
    std::vector<int> stack;

    int curr_min = 1;
    int sum = 0;
    while (curr_min < target) {
        sum += curr_min;
        if (sum >= target) {
            if (sum == target) {
                output.push_back(stack); // make a copy
                output.back().push_back(curr_min);
            }
            sum -= curr_min + stack.back();
            curr_min = stack.back() + 1;
            stack.pop_back();
        } else {
            stack.push_back(curr_min);
        }
    }

    return output;
}

int main()
{
    auto vvi = print_all_sum(6);

    for (auto const& v: vvi) {
        for(auto const& i: v) {
        std::cout << i;
        }
        std::cout << "\n";
    }

    return 0;
}

输出print_all_sum (6):

111111
11112
1113
1122
114
123
15
222
24
33

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

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

希望这能有所帮助。

首先推导0。0是加法的一个恒等式所以在这个特殊情况下,它在单类定律下是没有用的。如果你想向上爬到一个正数,也可以推导出负数。否则还需要做减法运算。

所以…在这个特定的作业中,你能得到的最快算法如下所示。

函数items2T ([n,……ns), t) { Var c = ~~(t/n); 返回ns。长度呢?数组(c + 1) .fill () .reduce((r,_,i) => r.concat(items2T(ns, t-n*i)。map(s => Array(i).fill(n).concat(s))),[]) : t % n ?[] :[数组(c) .fill (n)); }; Var数据= [3,9,8,4,5,7,10], 结果; console.time(“组合”); result = items2T(data, 15); console.timeEnd(“组合”); console.log (JSON.stringify(结果));

这是一个非常快的算法,但如果你对数据数组进行降序排序,它会更快。使用.sort()是无关紧要的,因为算法最终会减少递归调用。