Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP太慢了,有人能想出一个让它更快的方法吗?_Php_Performance - Fatal编程技术网

PHP太慢了,有人能想出一个让它更快的方法吗?

PHP太慢了,有人能想出一个让它更快的方法吗?,php,performance,Php,Performance,给定一个电话号码列表,确定该列表是否一致,即没有号码是另一个号码的前缀。假设电话目录中列出了以下号码: 紧急911 爱丽丝97625999 鲍勃91125426 在这种情况下,不可能给鲍勃打电话,因为只要你拨了鲍勃电话号码的前三位,中央就会将你的电话转到紧急电话线上。所以这个列表并不一致 输入 输入的第一行给出一个整数1≤T≤40,测试用例的数量。每个测试用例从n开始,电话号码的数量,在单独的一行上,1≤N≤10000然后跟随n行,每行上有一个唯一的电话号码。电话号码最多由十位数字组成 输出 对

给定一个电话号码列表,确定该列表是否一致,即没有号码是另一个号码的前缀。假设电话目录中列出了以下号码:

紧急911 爱丽丝97625999 鲍勃91125426

在这种情况下,不可能给鲍勃打电话,因为只要你拨了鲍勃电话号码的前三位,中央就会将你的电话转到紧急电话线上。所以这个列表并不一致

输入

输入的第一行给出一个整数1≤T≤40,测试用例的数量。每个测试用例从n开始,电话号码的数量,在单独的一行上,1≤N≤10000然后跟随n行,每行上有一个唯一的电话号码。电话号码最多由十位数字组成

输出

对于每个测试用例,如果列表一致,则输出“是”,否则输出“否”


程序应该从标准输入读取,并向标准输出写入。我们还可以假设输入将遵循规范。这是我的代码:

<?php

    fscanf(STDIN, "%d", $numOfTestCases);

    for ($i = 0; $i < $numOfTestCases; $i++) { //Loop for reading test cases
        fscanf(STDIN, "%d", $numOfPhoneNumbers);

        $phoneNumbers = array();
        $isConsistent = true;

        for ($j = 0; $j < $numOfPhoneNumbers; $j++) { //Loop for reading phone numbers of each test case
            fscanf(STDIN, "%d", $newNumber);

            if ($isConsistent != false) { //If list already inconsistent, we dont need to check further input
                if (empty($phoneNumbers)) { // If the array of phone numbers is empty, we just add the new one
                    $phoneNumbers[$j] = $newNumber;
                } else {
                    foreach ($phoneNumbers as $k => $testNumber) { //Loop for checking if new number is consistent or not
                        $newNumLen = strlen($newNumber);
                        $testNumlen = strlen($testNumber);

                        $newBeginning = substr($newNumber, 0, $testNumlen);
                        $testBeginning = substr($testNumber, 0, $newNumLen);

                        if ($newNumber == $testBeginning || $testNumber == $newBeginning) {
                            $isConsistent = false;
                            break;
                        }
                    }

                    if ($isConsistent == true) $phoneNumbers[$j] = $newNumber;
                }                   
            } 
        }

        $newAnswer = ($isConsistent) ? "YES" : "NO";
        $ansString = ($i == 0) ? $newAnswer : $ansString."\n".$newAnswer;
    }

    fwrite(STDOUT, $ansString);

    exit(0);
?>

正如大家所提到的,树是您的解决方案。 创建一棵树,每个节点代表数字中的一个数字。 每个数字中的最后一个数字将标记为isNumber=true,其余数字将标记为isNumber=false

向树添加编号时,遍历树的节点,并检查是否遍历isNumber=true的节点。如果是,则返回false/打印某些内容

例:见下面的插图

添加数字21:对数字进行迭代。创建新节点=1,新节点=2(isNumber=true)

添加数字911:重复数字。创建新节点=9,新节点=1,新节点=1(isNumber=true) 添加编号9125:对数字进行迭代。创建新节点=9,新节点=1,新节点=2,新节点=5(isNumber=true)

添加数字9112:在数字上迭代。创建新节点=9,新节点=1,新节点=1(错误:由于isNumber=true而失败)

希望能有点帮助

编辑:

好的,因为我对它感兴趣,所以我试着实现这个解决方案,我和你的非常接近

我制作了一个简单的脚本来创建一个包含10000个数字(1)的testcase.txt≤N≤10000)

我制作了一个简单的unittest.php脚本,可以运行40次(1)≤T≤40),在同一个文件中

<?php 

// create_testcase.php
$handle = fopen("testcase.txt",'w');

for($i=0 ; $i < 10000 ; $i++){
    $number = rand(1,9999999999);
    fwrite($handle,$number."\n");
}
fclose($handle);

// unittest.php
class Node{
    private $digit;
    private $leaf = false;
    private $children = array();
    function __construct($digit,$leaf = false){
        $this->digit = $digit;
        $this->leaf = $leaf;
    }

    function isLeaf(){
        return $this->leaf;
    }

    function hasChild($digit){
        return array_key_exists($digit,$this->children);

    }

    function hasChildren(){
        return count($this->children);
    }

    function addChild($digit,$isLeaf){
        $this->children[$digit] = new Node($digit,$isLeaf);
        return $this->children[$digit];
    }

    function getChild($digit){
        return $this->children[$digit];
    }

}


for($i=0 ; $i < 40 ; $i++){

    $anchor = new Node(0,false);
    $isConsistent = true;
    $handle = fopen("testcase.txt",'r');

    while(($number = fgets($handle)) != false){
        $node = $anchor;
        $number = rtrim($number);
        $number_length = strlen($number);
        foreach(str_split($number) as $index => $digit){
            if($node->hasChild($digit)){
                $node = $node->getChild($digit);
                if($node->isLeaf()){
                    $isConsistent = false;
                    break;
                }
            }
            else{
                (($index+1) == $number_length) ? ($isLeaf = true) : ($isLeaf = false);
                $node = $node->addChild($digit,$isLeaf);
            }   
        }

        if($node->hasChildren()){
            $isConsistent = false;      
        }

        if(!$isConsistent){
            break;                  // don't continue to next number in test case
        }
    }
    if($isConsistent){
        print "Consist list\n";

    }
    else{
        print "Not Consist list\n";
    }
    fclose($handle);

}

使用探查器。xdebug非常棒。你可以看到大部分时间都花在了哪里,我会使用一种完全不同的方法:目前你基本上是将每个数字与另一个数字进行比较,这会产生O(n^2)的复杂度。相反,您可以使用每个级别上的数字构建一个已知数字的树。当您在树中输入一个新号码,并且在途中遇到一个已知号码时,请拒绝该号码。这导致了几乎线性的复杂性。可能缓慢的部分是缓慢的、阻塞的、等待输入的STDIN read。您应该使用tree,而不是array[php]和[performance]永远都不是有效的组合非常感谢,这是最好的解决方案。现在我只需要拿出代码来做这件事。我试图用上面的方法来做一个解决方案,但我仍然有一个代码太慢,无法让测试程序超时4秒。我的新代码在这里:,你能发现我做错了什么吗?@YyYo漂亮的答案。:)
<?php 

// create_testcase.php
$handle = fopen("testcase.txt",'w');

for($i=0 ; $i < 10000 ; $i++){
    $number = rand(1,9999999999);
    fwrite($handle,$number."\n");
}
fclose($handle);

// unittest.php
class Node{
    private $digit;
    private $leaf = false;
    private $children = array();
    function __construct($digit,$leaf = false){
        $this->digit = $digit;
        $this->leaf = $leaf;
    }

    function isLeaf(){
        return $this->leaf;
    }

    function hasChild($digit){
        return array_key_exists($digit,$this->children);

    }

    function hasChildren(){
        return count($this->children);
    }

    function addChild($digit,$isLeaf){
        $this->children[$digit] = new Node($digit,$isLeaf);
        return $this->children[$digit];
    }

    function getChild($digit){
        return $this->children[$digit];
    }

}


for($i=0 ; $i < 40 ; $i++){

    $anchor = new Node(0,false);
    $isConsistent = true;
    $handle = fopen("testcase.txt",'r');

    while(($number = fgets($handle)) != false){
        $node = $anchor;
        $number = rtrim($number);
        $number_length = strlen($number);
        foreach(str_split($number) as $index => $digit){
            if($node->hasChild($digit)){
                $node = $node->getChild($digit);
                if($node->isLeaf()){
                    $isConsistent = false;
                    break;
                }
            }
            else{
                (($index+1) == $number_length) ? ($isLeaf = true) : ($isLeaf = false);
                $node = $node->addChild($digit,$isLeaf);
            }   
        }

        if($node->hasChildren()){
            $isConsistent = false;      
        }

        if(!$isConsistent){
            break;                  // don't continue to next number in test case
        }
    }
    if($isConsistent){
        print "Consist list\n";

    }
    else{
        print "Not Consist list\n";
    }
    fclose($handle);

}