我已经构建了一个类,它找到可以被给定范围内的所有数字整除的最小数字。
这是我的代码:
class SmallestDivisible
{
private $dividers = array();
public function findSmallestDivisible($counter)
{
$this->dividers = range(10, 20);
for($x=1; $x<$counter; $x++) {
if ($this->testIfDevisibleByAll($x, $this->dividers) == true) {
return $x;
}
}
}
private function testIfDevisibleByAll($x, $dividers)
{
foreach($dividers as $divider) {
if ($x % $divider !== 0) {
return false;
}
}
return true;
}
}
$n = new SmallestDivisible();
echo $n->findSmallestDivisible(1000000000);
此类找到一个可被1到20范围内的所有数字整除的数字($this->dividers
)。
我知道它运行良好,因为我用其他较低范围测试它,但不幸的是,它无法在30秒内找到range(10, 20)
的解决方案 - 这是PHP脚本之后的时间停了。
提供给findSmallestDivisible
方法的参数是脚本要检查的数字组的上限(ei从1到$counter
(1000000000就是这个执行)。)
我很感激有关如何优化此脚本以便更快执行的建议。
答案 0 :(得分:3)
你的解决方案是蛮力的,简直太糟糕了。
相反,如何以数学方式处理它?您正在寻找您所在范围内最低的常用数字,因此......
function gcd($n, $m) {
$n=abs($n); $m=abs($m);
list($n,$m) = array(min($m,$n),max($m,$n));
while($r = $m % $n) {
list($m,$n) = array($n,$r);
}
return $n;
}
function lcm($n, $m) {
return $m * ($n/gcd($n,$m));
}
function lcm_array($arr) {
while(count($arr) > 1) {
array_push($arr, lcm(array_shift($arr),array_shift($arr)));
}
return array_shift($arr);
}
var_dump(lcm_array(range(10,20)));
// result int(232792560)
这意味着您的原始代码必须进行232,792,560次迭代,难怪花了这么长时间!
答案 1 :(得分:1)
你的目标是一个名为the least common multiple的简单数学计算,但使用蛮力来计算它是完全错误的(正如你已经发现的那样)。
Wikipedia page列出了几种可用于更快地计算它的合理算法。
“A method using a table”一节中解释的那个非常快,并且不需要太多内存。您只保留表格的最左侧列(要获取lcm
的数字)和最右侧的列(当前步骤)。如果您实现它,我建议您将prime numbers的列表硬编码到您的程序中,以避免计算它们。
答案 2 :(得分:0)
这是我提出的另一种解决方案。
简而言之,该算法将为一组数字计算LCM(最小公倍数)。
class Lcmx
{
public $currentLcm = 0;
private function gcd($a, $b)
{
if ($a == 0 || $b == 0)
return abs( max(abs($a), abs($b)) );
$r = $a % $b;
return ($r != 0) ?
$this->gcd($b, $r) :
abs($b);
}
private function lcm($a, $b)
{
return array_product(array($a, $b)) / $this->gcd($a, $b);
}
public function lcm_array($array = array())
{
$factors = $array;
while(count($factors) > 1) {
$this->currentLcm = $this->lcm(array_pop($factors), array_pop($factors));
array_push($factors, $this->currentLcm);
}
return $this;
}
}
$l = new Lcmx;
echo $l->lcm_array(range(1, 20))->currentLcm;
//232792560