我目前正在计算一组数据的唯一排列。虽然下面的代码有效,但它没有我想要的那么高效。一旦我得到超过 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
函数中,它会运行超过 100k 次才能找到 840 个唯一排列。
我想找到一种方法来减少这种情况并找到唯一排列的最短路径。感谢您提供的任何帮助或建议。
最佳答案
所以我花了更多时间思考这个问题,这就是我的想法。
<?php
function permuteUnique($items, $perms = [], &$return = []) {
if (empty($items)) {
$return[] = $perms;
} else {
sort($items);
$prev = false;
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$tmp = array_splice($newitems, $i, 1)[0];
if ($tmp != $prev) {
$prev = $tmp;
$newperms = $perms;
array_unshift($newperms, $tmp);
permuteUnique($newitems, $newperms, $return);
}
}
return $return;
}
}
$permutations = permuteUnique([1, 2, 2, 3, 4, 4, 4, 4]);
以前的统计数据
Uniques: 840
Calls to permuteUnique: 107,591
Duplicates found: 38737
Execution time (seconds): 4.898668050766
新统计数据
Uniques: 840
Calls to permuteUnique: 2647
Duplicates found: 0
Execution time (seconds): 0.0095300674438477
所以我真正做的就是对数据集进行排序,跟踪前一项,如果当前项与前一项匹配则不计算排列。我也不再需要预先计算唯一值的数量并遍历排列以检查重复项。这让世界变得不同。
关于php - 有效计算集合中的唯一排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18935813/