优化PHP算法

时间:2015-03-05 14:39:12

标签: php algorithm

我已经构建了一个类,它找到可以被给定范围内的所有数字整除的最小数字。

这是我的代码:

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就是这个执行)。)

我很感激有关如何优化此脚本以便更快执行的建议。

3 个答案:

答案 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