我有0到8的数字。 我希望得到所有可能的数字集合,每个集合应使用所有数字,每个数字在一个集合中只能出现一次。
我想看到用PHP编写的解决方案,可以打印出结果。或者,至少我想要一些组合数学理论的复习,因为我已经很久没有接触了。如何计算全排列的公式是什么?
示例集:
- 0-1-2-3-4-5-6-7-8
- 0-1-2-3-4-5-6-8-7
- 0-1-2-3-4-5-8-6-7
- 0-1-2-3-4-8-5-6-7
- 0-1-2-3-8-4-5-6-7
- 0-1-2-8-3-4-5-6-7
- 等等...
我有0到8的数字。 我希望得到所有可能的数字集合,每个集合应使用所有数字,每个数字在一个集合中只能出现一次。
我想看到用PHP编写的解决方案,可以打印出结果。或者,至少我想要一些组合数学理论的复习,因为我已经很久没有接触了。如何计算全排列的公式是什么?
示例集:
你正在寻找排列组合公式:
nPk = n!/(n-k)!
在您的情况下,您有9个条目并且希望选择它们全部,即9P9 = 9!= 362880。
您可以在O'Reilly的“PHP Cookbook”中的配方4.26中找到一个用于排列的PHP算法。
pc_permute(array(0, 1, 2, 3, 4, 5, 7, 8));
从 O'Reilly 复制而来:
function pc_permute($items, $perms = array( )) {
if (empty($items)) {
print join(' ', $perms) . "\n";
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
pc_permute($newitems, $newperms);
}
}
}
function permutations(array $elements)
{
if (count($elements) <= 1) {
yield $elements;
} else {
foreach (permutations(array_slice($elements, 1)) as $permutation) {
foreach (range(0, count($elements) - 1) as $i) {
yield array_merge(
array_slice($permutation, 0, $i),
[$elements[0]],
array_slice($permutation, $i)
);
}
}
}
}
使用示例:
$list = ['a', 'b', 'c'];
foreach (permutations($list) as $permutation) {
echo implode(',', $permutation) . PHP_EOL;
}
输出:
a,b,c
b,a,c
b,c,a
a,c,b
c,a,b
c,b,a
由于此问题经常出现在Google搜索结果中,因此这里提供了一个修改后的答案,它将所有组合作为数组返回,并将它们作为函数的返回值传递。
function pc_permute($items, $perms = array( )) {
if (empty($items)) {
$return = array($perms);
} else {
$return = array();
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
$return = array_merge($return, pc_permute($newitems, $newperms));
}
}
return $return;
}
使用方法:
$value = array('1', '2', '3');
print_r(pc_permute($value));
ini_set('memory_limit', -1);
(注:这是一段PHP代码,意为设置内存限制为无限制。) - verbumSapienti我有一些东西,可能会对您感兴趣。
function combination_number($k,$n){
$n = intval($n);
$k = intval($k);
if ($k > $n){
return 0;
} elseif ($n == $k) {
return 1;
} else {
if ($k >= $n - $k){
$l = $k+1;
for ($i = $l+1 ; $i <= $n ; $i++)
$l *= $i;
$m = 1;
for ($i = 2 ; $i <= $n-$k ; $i++)
$m *= $i;
} else {
$l = ($n-$k) + 1;
for ($i = $l+1 ; $i <= $n ; $i++)
$l *= $i;
$m = 1;
for ($i = 2 ; $i <= $k ; $i++)
$m *= $i;
}
}
return $l/$m;
}
function array_combination($le, $set){
$lk = combination_number($le, count($set));
$ret = array_fill(0, $lk, array_fill(0, $le, '') );
$temp = array();
for ($i = 0 ; $i < $le ; $i++)
$temp[$i] = $i;
$ret[0] = $temp;
for ($i = 1 ; $i < $lk ; $i++){
if ($temp[$le-1] != count($set)-1){
$temp[$le-1]++;
} else {
$od = -1;
for ($j = $le-2 ; $j >= 0 ; $j--)
if ($temp[$j]+1 != $temp[$j+1]){
$od = $j;
break;
}
if ($od == -1)
break;
$temp[$od]++;
for ($j = $od+1 ; $j < $le ; $j++)
$temp[$j] = $temp[$od]+$j-$od;
}
$ret[$i] = $temp;
}
for ($i = 0 ; $i < $lk ; $i++)
for ($j = 0 ; $j < $le ; $j++)
$ret[$i][$j] = $set[$ret[$i][$j]];
return $ret;
}
以下是如何使用它:
获取组合数的方法:
combination_number(3,10); // returns number of combinations of ten-elements set.
获取所有可能的组合:
要获取所有可能的组合:
$mySet = array("A","B","C","D","E","F");
array_combination(3, $mySet); // returns all possible combinations of 3 elements of six-elements set.
希望你能好好利用它。
我已经将列在这里的Python itertools代码(使用生成器)移植过来。与迄今所发布的解决方案相比,其优点在于它允许您指定r(排列大小)。
function permutations($pool, $r = null) {
$n = count($pool);
if ($r == null) {
$r = $n;
}
if ($r > $n) {
return;
}
$indices = range(0, $n - 1);
$cycles = range($n, $n - $r + 1, -1); // count down
yield array_slice($pool, 0, $r);
if ($n <= 0) {
return;
}
while (true) {
$exit_early = false;
for ($i = $r;$i--;$i >= 0) {
$cycles[$i]-= 1;
if ($cycles[$i] == 0) {
// Push whatever is at index $i to the end, move everything back
if ($i < count($indices)) {
$removed = array_splice($indices, $i, 1);
array_push($indices, $removed[0]);
}
$cycles[$i] = $n - $i;
} else {
$j = $cycles[$i];
// Swap indices $i & -$j.
$i_val = $indices[$i];
$neg_j_val = $indices[count($indices) - $j];
$indices[$i] = $neg_j_val;
$indices[count($indices) - $j] = $i_val;
$result = [];
$counter = 0;
foreach ($indices as $indx) {
array_push($result, $pool[$indx]);
$counter++;
if ($counter == $r) break;
}
yield $result;
$exit_early = true;
break;
}
}
if (!$exit_early) {
break; // Outer while loop
}
}
}
这对我来说可行,但不保证适用于所有情况! 使用示例:
$result = iterator_to_array(permutations([1, 2, 3, 4], 3));
foreach ($result as $row) {
print implode(", ", $row) . "\n";
}
这是我编写的一个类。该类生成并返回排列后的数组作为结果。
class Permutation {
private $result;
public function getResult() {
return $this->result;
}
public function permute($source, $permutated=array()) {
if (empty($permutated)){
$this->result = array();
}
if (empty($source)){
$this->result[] = $permutated;
} else {
for($i=0; $i<count($source); $i++){
$new_permutated = $permutated;
$new_permutated[] = $source[$i];
$new_source = array_merge(array_slice($source,0,$i),array_slice($source,$i+1));
$this->permute($new_source, $new_permutated);
}
}
return $this;
}
}
$arr = array(1,2,3,4,5);
$p = new Permutation();
print_r($p->permute($arr)->getResult());
以下是一个简单的递归函数,用于打印所有排列组合(伪代码)
function rec(n, k) {
if (k == n) {
for i = 0 to n-1
print(perm[i], ' ');
print('\n');
}
else {
for i = 0 to n-1 {
if (not used[i]) {
used[i] = true;
perm[k] = i;
rec(n, k+1);
used[i] = false;
}
}
}
}
这样称呼它:
rec(9, 0);
字典序排序。没有递归。数组长度几乎没有限制。没有排序,运行非常快。易于理解。 缺点:它会发出一个通知,但是您可以添加条件来从第二个元素开始比较或使用error_reporting(0)。
$a = array(
1,
2,
3,
4,
5
);
$b = array_reverse($a);
print_r($a);
//here need "br"
while ($a != $b)
{
foreach(array_reverse($a, true) as $k => $v)
{
if ($v < $a[$k + 1])
{
foreach(array_reverse($a, true) as $ka => $val)
{
if ($val > $v) break;
}
$ch = $a[$k];
$a[$k] = $a[$ka];
$a[$ka] = $ch;
$c = array_slice($a, 0, $k + 1);
print_r($a = array_merge($c, array_reverse(array_slice($a, $k + 1))));
//here need "br"
break;
}
}
}
if (isset($a[$key + 1]) && $value < $a[$key + 1]) {
(太短无法编辑 :) - Rarst这是我的建议,希望比接受的答案更加清晰明了。
function permutate($elements, $perm = array(), &$permArray = array())
{
if(empty($elements))
{
array_push($permArray,$perm); return;
}
for($i=0;$i<=count($elements)-1;$i++)
{
array_push($perm,$elements[$i]);
$tmp = $elements; array_splice($tmp,$i,1);
permutate($tmp,$perm,$permArray);
array_pop($perm);
}
return $permArray;
}
和用法:
$p = permutate(array('a','b','c'));
foreach($p as $perm)
print join(",",$perm)."|\n";
x^0 = 1
一样(除了当x = 0
时,因为0^0 = 0
)。 - poke