現在、データ配列の固有の順列を計算しています。次のコードは動作していますが、私が望むほど効率的ではありません。一度私が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
パラメータであるI関数に期待し、いったんそれが多く見つかったら、それは計算を停止してデータを返すことができます。これは、アイテムの総数の階乗を、すべての重複のカウントの階乗の積で除したものとして計算されます。私はそのことを正しく言っているかどうか分からないので、例を見せてください。セット[1, 2, 2, 3, 4, 4, 4, 4]
ユニークな順列の数が合計8つの項目、そのうちの一つが二回重複しているがありますので 8!/(2!4!) = 840
として計算され、そして別のは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
関数にカウンタを投げた場合、それは840個のユニークな順列を見つける前に100k回以上実行されます。
これを減らし、一意の置換への最短経路を見つける方法を探したいと思います。私はあなたに与えることのできる助けやアドバイスを感謝します。
C++の['std :: next_permutation'](http://en.cppreference.com/w/cpp/algorithm/next_permutation)を見て、PHPのようなものを見つけて実装してください。 – MvG