不是置换原始数字字符串,而是置换数字组。我不知道如何最好地描述它,所以我会尝试一些伪代码。
对于字符串“001222”,数字组是两个 0、一个 1 和三个 2。
permute(groups, permutation):
if there are no non-empty groups
print permutation
else
for each non-empty group
permutation += group.digit
--group.count
permute(groups, permutation)
通过循环组而不是所有数字,它可以避免生成重复,因为每个数字只能为下一个位置选择一次,而不是多次。遍历你得到的随机排列
Permutation Digit Groups
0: 2, 1: 1, 2: 3 // start
0 0: 1, 1: 1, 2: 3
02 0: 1, 1: 1, 2: 2 // *
021 0: 1, 1: 0, 2: 2 // the 1 group is removed from the set
0212 0: 1, 1: 0, 2: 1
02120 0: 0, 1: 0, 2: 1 // the 0 group is removed from the set
021202 0: 0, 1: 0, 2: 0 // the 2 group is removed from the set
现在展开回 *.
02 0: 1, 1: 0, 2: 1
因为您循环的是数字组而不是原始字符串中的所有(重复)数字,所以您不能再次选择 2。这意味着所有以“02”开头的排列都是唯一的,因为前缀“02”只生成一次。这同样适用于整个算法。
更新
这是一个快速的 PHP 实现,它为输入“001222”产生 60 个排列:
function permute(&$groups, &$count, $permutation) {
$done = true;
foreach ($groups as &$group) {
if ($group[1] > 0) {
--$group[1];
permute($groups, $count, $permutation . $group[0]);
++$group[1];
$done = false;
}
}
if ($done) {
echo $permutation . PHP_EOL;
++$count;
}
}
$groups = array(
array(0, 2),
array(1, 1),
array(2, 3),
);
$count = 0;
permute($groups, $count, '');
echo "\nTotal: $count\n";