如何在 PHP 中找到所有 N 个单位数、非重复数字的总和?
Posted
技术标签:
【中文标题】如何在 PHP 中找到所有 N 个单位数、非重复数字的总和?【英文标题】:How would I find all sets of N single-digit, non-repeating numbers that add up to a given sum in PHP? 【发布时间】:2011-02-15 06:43:55 【问题描述】:假设我想找到所有 5 个单数、非重复数字加起来为 30... 我最终会得到 [9,8,7,5,1], [9, 8,7,4,2],[9,8,6,4,3],[9,8,6,5,2],[9,7,6,5,3] 和 [8,7 ,6,5,4]。这些集合中的每一个都包含 5 个不重复的数字,它们加起来为 30,即给定的总和。
任何帮助将不胜感激。即使只是我使用的一个起点也很棒。
我想出了一个方法,这似乎是一个很长的路要走:获取所有唯一的 5 位数字(12345、12346、12347 等),将这些数字相加,看看它是否等于给定总和(例如 30)。如果是,请将其添加到可能的匹配集列表中。
我这样做是为了一个个人项目,这将帮助我解决 Kakuro 谜题,而无需一次真正解决整个问题。是的,它可能是作弊,但它......它不是那么糟糕......:P
【问题讨论】:
【参考方案1】:一种天真的方法是将变量从12345
递增到98765
,并且仅当它具有唯一数字且数字总和为30
时才选择它:
for($i=12345;$i<98765;$i++)
$arr = preg_split('//',strval($i));
if(count(array_unique($arr)) == count($arr) && array_sum($arr) == 30)
echo $i."\n";
Working example
【讨论】:
我已经简化了你的例子,unicornaddict:ideone.com/cUaaH我实际上认为这是正确的轨道。我需要做的就是通过对数字进行排序来消除重复项(如 15789 和 15798,它们包含相同的数字),并检查排序后的数组以查看它是否以前返回。 BAM:ideone.com/Y91ZX 完美运行,主要感谢您的回答,独角兽!非常感谢!也都在 20 行以下。 :D 考虑到创建唯一数组的开销,首先在条件中执行array_sum
可能更快。
好主意!它不应该做它不需要做的昂贵的操作。谢谢!
迭代到 56789 还不够吗?我相信所有高于 56789 的数字都将是低于 56789 的数字的排列。这应该将迭代长度减半。另外,我认为for循环的结束条件应该是$i<=
,而不是$i<
,你要确保测试结束数字。【参考方案2】:
function sumOfDigits($num)
$str = "$num";
$sum = 0;
for ($i=0;$i<strlen($str);$i++)
$sum += (int)substr($str, $i, 1);
return $sum;
function hasDuplicateDigits($num)
$str = "$num";
$pieces = array();
for ($i=0;$i<strlen($str);$i++)
$pieces[] = substr($str, $i, 1);
return (count(array_unique($pieces)) != strlen($str));
// if you prefer the opposite function
function hasAllUniqueDigits($num)
return (!hasDuplicateDigits($num));
$numbers = range(10000, 99999);
foreach ($numbers as $num)
if ( !hasDuplicateDigits($num) && (sumOfDigits($num) == 30))
print $num . "\n";
【讨论】:
如果我处理数组,其中一些是内置在 php 中的。请参阅ideone.com/cUaaH 了解更多信息。不过还是谢谢你的回答!它也会有所帮助,因为我不知道 range() 函数。 :D【参考方案3】:这可能已经足够快了:
<?php
$digitCount = 5;
$sum = 30;
function getAnswer($b)
$a = "";
$i = 1;
while ($b)
if ($b & 1) $a .= "$i ";
$b >>= 1;
++$i;
return $a;
for ($b = 0; $b < 512; ++$b)
$v = 0;
$c = 0;
$i = 1;
$s = $b;
while ($s)
if ($s & 1)
if (++$c > $digitCount) continue 2;
$v += $i;
$s >>= 1;
++$i;
if ($c == $digitCount && $v == $sum)
echo getAnswer($b)."\n";
?>
【讨论】:
【参考方案4】:使用来自here的组合代码
foreach(new Combinations("123456789", 5) as $p)
$r[array_sum(str_split($p))] .= "$p ";
print_r($r);
结果
[15] => 12345
[16] => 12346
[17] => 12347 12356
[18] => 12348 12357 12456
[19] => 12349 12358 12367 12457 13456
[20] => 12359 12368 12458 12467 13457 23456
[21] => 12369 12378 12459 12468 12567 13458 13467 23457
[22] => 12379 12469 12478 12568 13459 13468 13567 23458 23467
[23] => 12389 12479 12569 12578 13469 13478 13568 14567 23459 23468 23567
[24] => 12489 12579 12678 13479 13569 13578 14568 23469 23478 23568 24567
[25] => 12589 12679 13489 13579 13678 14569 14578 23479 23569 23578 24568 34567
[26] => 12689 13589 13679 14579 14678 23489 23579 23678 24569 24578 34568
[27] => 12789 13689 14589 14679 15678 23589 23679 24579 24678 34569 34578
[28] => 13789 14689 15679 23689 24589 24679 25678 34579 34678
[29] => 14789 15689 23789 24689 25679 34589 34679 35678
[30] => 15789 24789 25689 34689 35679 45678
[31] => 16789 25789 34789 35689 45679
[32] => 26789 35789 45689
[33] => 36789 45789
[34] => 46789
[35] => 56789
是不是很可爱?
【讨论】:
【参考方案5】:我知道有一些算法可以解决这个问题,它们可能会由其他人提供,但您可以做一个简单的快速简化:查找所有 4 个单位数字加起来为 21-29 的集合(我假设你没有把 0 算作一个数字),而只是消除了 30-(总和)是其中一个数字的那些。
如果我想更快地尝试一些东西,我会考虑从 45678 开始,然后通过将一个数字加 1 并从另一个数字减 1 来逐步改变它。不过,不确定最终效果如何。
【讨论】:
我想一种方法是找到一个匹配集,然后对称地添加/减去数字以找到其他集。【参考方案6】:我相信这被称为子集和问题:
http://mathworld.wolfram.com/SubsetSumProblem.html
【讨论】:
【参考方案7】:让我们写 f(30,5,1) 来回答您的问题。 30 表示所需的总和,5 表示应添加到所需总和的位数,1 表示可接受的最小位数。在这种形式下,您可以递归地解决问题。例如,
f(30,5,b) = sum(i = 1..9) f(30-i,4,i+1)
我们实际上已经耗尽了您寻找的组合中出现的最低值 i。 如果您更仔细地考虑 i 的最大可能值(它不能太大,因为它是数字中的最小值),并添加一些适当的救助条件,那么您将有一个非常快速的解决方案。
【讨论】:
【参考方案8】:打印数字的总和形成一个由 n 个数字组成的数组,其中没有重复的数字。例如 输入:[100、213、414、555、62、321]
输出:596(即 213+62+321)
【讨论】:
您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。以上是关于如何在 PHP 中找到所有 N 个单位数、非重复数字的总和?的主要内容,如果未能解决你的问题,请参考以下文章
给定数组和一个常量,从数组中找到两个数之和等于常量,如何做最快