Локаль, но дело не в ней а в том чтоб прогнать алгоритмы под одним стеком. https://sandbox.onlinephpfunctions.com/ время 0.0084900856018066 всего 29116
Не думаю что у всех кардинально разное решение. Судя по всему (в том числе по времени) примерно одинаковое.. Небольшая разница в реализации скорее всего есть, где какие функции использовали итд.. так что не вижу смысла мерятся письками. Вот если у кого то появится результат на порядки быстрее работающего, то вот там скорее всего какое то существенное изменение алгоритма
Там даже между массивом в 10к разных элементов и массивом в 5 единичек разницы на порядки нет... Так что, имхо, выжимать соки дальше некуда. Алгоритм уже и так предельно на пределе. Хоть сколько на спичках не экономь
обнаружил что online php ограничивает размер кода. с данными я превышаю квоту примерно в два раза. думал выкрутиться через чтение данных с внешнего API, а он такой как выкручиваетесь?
мой код http://sandbox.onlinephpfunctions.com/code/5567aad4055aa735f6f6fe07e241749deaebfdf1 данные можно было БЫ тянуть отсюда как json. --- Добавлено --- уже рахзобрались - на запуск не ограничивает, но на расшаривание органичивает. поэтому шарить можно только заготовку без данных. --- Добавлено --- скопипастить массив можно открыв вот такое в браузере view-source:https://api.jsonbin.io/b/5fe2091387e11161f87dbe4f
http://sandbox.onlinephpfunctions.com/code/6518e096d5c5a7d5866b4a70068946d28cf3d160 Fell успешно нарыл natsort, что удешевляет.
Мой вариант https://sandbox.onlinephpfunctions.com/code/b0cb4b25b719807fde79087377e0a9a4f45a402a 9999 29116 0.008296012878418
Массив нужно вставить на место вызова get_array() в самом начале https://bit.ly/3pfhsAI 29116 Лучше время 0.0075 В среднем 0.0085
При замене цифр на буквы, это выглядит единственным способом ускорить алгоритм https://sandbox.onlinephpfunctions.com/code/fc4170260277f0ffa563aca2351ee71188ad1520
Код (Text): <?php function bmark() { $args = func_get_args(); $len = count($args); if ($len < 3) { trigger_error("At least 3 args expected. Only $len given.", 256); return false; } $cnt = array_shift($args); $fun = array_shift($args); $start = microtime(true); $i = 0; while ($i < $cnt) { $i++; $res = call_user_func_array($fun, $args); } $end = microtime(true) - $start; return $end; } //функция для конвертации времени, принимает значения в секундах function convert_time($time) { if ($time == 0) { return 0; } $unit = array(-4 => 'ps', -3 => 'ns', -2 => 'mcs', -1 => 'ms', 0 => 's'); $i = min(0, floor(log($time, 1000))); $t = @round($time / pow(1000, $i), 1); return $t . $unit[$i]; } /////////////// ////////////// ///////////// /// ПЕРВЫЙ ВАРИАНТ function anagrams($a) { // count repeated values $counts = array_count_values( // make anagram items equal array_map(function ($item) { $array = str_split((string) $item); sort($array); return join($array); }, $a) ); // sum of pairs $result = 0; foreach ($counts as $n) { if ($n < 2) continue; $result += pairCount($n); } return $result; } function pairCount($n) { static $cache = [0, 0]; return $cache[$n] ?? $cache[$n] = pairCount($n - 1) + $n - 1; } ////ПЕРВЫЙ КОНЕЦ ////ВТОРОЙ ВАРИАНТ function cnt(int $dupli): int{ $c = 0; for($i = 1; $i < $dupli; ++$i){ $c += $i; } return $c; } function count_anagra(array $a): int{ $res = []; foreach($a as $e){ $digs = str_split((string)$e); sort($digs); $key = implode($digs); if (isset($res[$key])){ ++$res[$key]; }else{ $res[$key] = 1; } } return array_sum(array_map('cnt', $res)); } ///ВТОРОЙ ВАРИАНТ КОНЕЦ ///ТРЕТИЙ ВАРИАНТ function count_anagra2(array $a): int{ array_walk($a, function (&$i) { $a = str_split((string)$i); sort($a); $i = implode($a); } ); $a = array_count_values($a); array_walk($a, function (int &$dupli): void{ $c = 0; for($i = 1; $i < $dupli; ++$i){ $c += $i; } $dupli = $c; } ); return array_sum($a); } ///ТРЕТИЙ ВАРИАНТ КОНЕЦ ////СРАВНЕНИЕ $rounds = 100; $a = array_keys(array_fill(0,1e4,null)); echo str_pad("anagrams() dataset \$a result: ", 45) . anagrams($a) . PHP_EOL; echo str_pad("anagrams() dataset \$a: ", 45) . convert_time(bmark($rounds, "anagrams", $a) / $rounds) . PHP_EOL; echo str_pad("count_anagra() dataset \$a result: ", 45) . count_anagra($a) . PHP_EOL; echo str_pad("count_anagra() dataset \$a: ", 45) . convert_time(bmark($rounds, "count_anagra", $a) / $rounds) . PHP_EOL; echo str_pad("count_anagra2() dataset \$a result: ", 45) . count_anagra2($a) . PHP_EOL; echo str_pad("count_anagra2() dataset \$a: ", 45) . convert_time(bmark($rounds, "count_anagra2", $a) / $rounds) . PHP_EOL; Первый вариант - чужой. Второй и третий - мой. Сразу посмотреть можно тут: http://sandbox.onlinephpfunctions.com/code/891add2f8914f287cbb48a1b9aa40ddf9d55fd1a
Код (Text): function count_anagra3(array $a): int{ array_walk($a, function (&$i) { $a = str_split((string)$i); rsort($a); $i = (int)implode($a); } ); $a = array_count_values($a); array_walk($a, function (int &$i): void{ $i = ($i - 1) / 2 * $i; } );
Подпилил еще немного. Код (Text): function count_anagra4(array $a): int{ $res = []; foreach($a as $e){ $digs = str_split((string)$e); rsort($digs); $key = (int)implode($digs); $res[$key] = isset($res[$key]) ? $res[$key] + 1 : 1; } return array_reduce($res, function (int $carry, int $i): int{ return $carry + ($i - 1) / 2 * $i; } , 0); }
Ну что ребятишки, вот и мое решение.... отличие - пытался делать максимально понятным и наглядным. чтоб было видно алгоритм, а не всякие ухищрения - насчет поменьше символов или использования всяких супер-функций php (хотя без них тоже не обошлось) Сравнивая ранее предложенные - все разбивают на цифры через строки, потому что проще видимо.... я работаю с числами - имхо работа с числами должна быть быстрее... больше сказать нечего ))) PHP: $input = json_decode(file_get_contents('test-1000.json')); // Выделяем цифры из числа и составляем новое число - в порядке возрастания цифр, // получаем эдакий хеш числа, у анаграмм - он одинаковый function digits($a){ $digits = []; while ($a>9) { $digit = $a % 10; $a = ($a - $digit)/10; $digits[] = $digit; } $digits[] = $a; sort($digits); return implode('',$digits); } // оптимизированная функция подсчета кол-ва сочетаний из N по 2 без повторений function C_N_2($x){ return $x*($x-1)/2; } // Начинаем подсчет времени $start = microtime(true); // заменяем числа в массиве на их "хэш-анаграммы" $output = array_map('digits',$input); // Тут для каждого хеша анаграммы - количество его повторений в массиве $output = array_count_values($output); // вычисляем для каждого кол-во сочетаний по 2 из N и суммируем $sum = 0; foreach ($output AS $item) { $sum += C_N_2($item); } echo 'Result = '.$sum . '<br/>'; $finish = microtime(true); $delta = $finish - $start; echo $delta . ' сек.';
Код (Text): function digits($a){ $digits = []; while ($a>9) { $digit = $a % 10; $a = ($a - $digit)/10; $digits[] = $digit; } $digits[] = $a; sort($digits); return implode('',$digits); } Красивый способ. Получилось ли быстрее, чем просто делать str_split()?
Не думаю что существенно на этом наборе данных... Просто вспомнил олимпиадные задачки в школе, когда в задачу добавлялось, что использование преобразователь чисел в строку и обратно запрещено
Хороже же ты учился. ) Близко такой х. не было в школе. Тоже люблю такую олимпиадную дребедень. Приколько было бы порешать задачи по ООП. Не представляю только, можно ли такие придумать.