В настоящее время я вычисляю уникальные перестановки массива данных. Хотя следующий код работает, он не так эффективен, как хотелось бы. Как только я получаю более 6 или 8 элементов, он становится очень медленным, и я начинаю сталкиваться с проблемами памяти.Эффективное вычисление уникальных перестановок в наборе
Вот код и объяснение
<?php
function permuteUnique($items, $count = false, $perms = [], &$return = []) {
if ($count && count($return) == $count) return $return;
if (empty($items)) {
$duplicate = false;
foreach ($return as $a) {
if ($a === $perms) {
$duplicate = true;
break;
}
}
if (!$duplicate) $return[] = $perms;
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($tmp) = array_splice($newitems, $i, 1);
array_unshift($newperms, $tmp);
permuteUnique($newitems, $count, $newperms, $return);
}
return $return;
}
}
function factorial($n) {
$f = 1;
for ($i = 2; $i <= $n; $i++) $f *= $i;
return $f;
}
Учитывая вход [1, 1, 2]
я получаю следующий результат, как ожидается,
array (size=3)
0 =>
array (size=3)
0 => int 1
1 => int 1
2 => int 2
1 =>
array (size=3)
0 => int 1
1 => int 2
2 => int 1
2 =>
array (size=3)
0 => int 2
1 => int 1
2 => int 1
Параметр $count
так я могу передать количество уникальных перестановок я ожидают функции, и как только она обнаружит, что многие, она может прекратить вычислять и возвращать данные. Это вычисляется как факториал от общего количества элементов, деленное на произведение факториала счета всех дубликатов. Я не уверен, что правильно сказал, поэтому позвольте мне показать вам пример.
Учитывая множество [1, 2, 2, 3, 4, 4, 4, 4]
подсчета уникальных перестановок рассчитываются как 8!/(2!4!) = 840
, потому что есть всего 8 пунктов, один из них дублируются в два раза, а другой дублируются 4 раза.
Теперь, если я перевожу, что PHP код ...
<?php
$set = [1, 2, 2, 3, 4, 4, 4, 4];
$divisor = 1;
foreach (array_count_values($set) as $v) {
$divisor *= factorial($v);
}
$count = factorial(count($set))/$divisor;
$permutations = permuteUnique($set, $count);
это довольно медленно. Если я закрою счетчик в функции permuteUnique
, он будет работать более 100 тыс. Раз, прежде чем он найдет 840 уникальных перестановок.
Я хотел бы найти способ уменьшить это и найти кратчайший путь к уникальным перестановкам. Я ценю любую помощь или совет, которые вы можете дать.
Посмотрите на ['std :: next_permutation'] (http://en.cppreference.com/w/cpp/algorithm/next_permutation) для C++ и найдите или реализуйте что-то подобное для PHP. – MvG