5

我在网上到处找这个,但无法完全找到。(我的 PHP 和数学技能让我对此感到失望......)我有一个数组,其中包含例如三个字符串(也可能更多!)(例如:“a”、“b”、“c”)。现在我想做一个返回所有可能性的函数。我到处寻找,发现了一些不错的函数,它们以所有可能的方式移动了数组,但它们并没有一个一个地删除一个值。所以他们有:

abc acb bac bca 出租车 cba

这很好,但我需要一个将其提升到新水平的函数:

abc acb bac bca cab cba ac ca ab ba bc ba abc

这不管有多少值(比如说最大 10)。我整个晚上都在为此苦苦挣扎,有人可以让我摆脱痛苦并为我解开这个谜语吗?或者给点建议。谢谢

4

3 回答 3

1

看起来您要的是“电源组”。幂集包括空集,我不会包括在内。

require_once 'Math/Combinatorics.php';
$set = range('a', 'c');
$permutationSizes = range(1, count($set));
$combinatorics = new Math_Combinatorics;
$result = array();
foreach ($permutationSizes as $permutationSize) {
    $result = array_merge($result, $combinatorics->permutations($set, $permutationSize));
}
print_r($result);

http://pear.php.net/package/Math_Combinatorics

我想从技术上讲这不是一个电源组,因为我假设在比较组时顺序很重要。反正...

于 2012-05-20T21:31:32.597 回答
1

与往常一样,以自己的方式解决问题更有趣。您可以更轻松地修改代码以满足您的特殊需求,因为您知道自己在做什么:) 请参阅下面的测试脚本:

<?

$a = array("a", "b", "c");

function getAll($prefix, $remaining)
{
    echo $prefix."\n";

    if (count($remaining) == 0) return;
    if (count($remaining) == 1)
    {                                                                
        echo $prefix.$remaining[0]."\n";
        return;                                                      
    }                                                                

    for ($i = 0; $i < count($remaining); $i++)                       
    {                                                                
        $t = $remaining;                                             
        unset($t[$i]);                                               
        $t = array_values($t);                                       
        getAll($prefix.$remaining[$i], $t);              
    }                                                                                                       
}                                                        
echo "<pre>\n";                                          
getAll('', $a);                                          
echo "</pre>\n";                                         

?>

我只是回显了预期的输出,你可以添加一个结果数组,但那是你的部分:)

输出:

[] //empty value is included, but blank lines won't show up here, so I wrote []
a
ab
abc
ac
acb
b
ba
bac
bc
bca
c
ca
cab
cb
cba
于 2012-05-21T05:53:02.157 回答
0

O'Reilly 的PHP Cookbook 第 4.26 节有一个用于排列的示例函数。它只创建固定大小的排列,但可以在循环中使用以处理您需要的任何大小。

代码

function pc_next_permutation($p, $size) {
    // slide down the array looking for where we're smaller than the next guy
    for ($i = $size - 1; $p[$i] >= $p[$i+1]; --$i) { }

    // if this doesn't occur, we've finished our permutations
    // the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
    if ($i == -1) { return false; }

    // slide down the array looking for a bigger number than what we found before
    for ($j = $size; $p[$j] <= $p[$i]; --$j) { }

    // swap them
    $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;

    // now reverse the elements in between by swapping the ends
    for (++$i, $j = $size; $i < $j; ++$i, --$j) {
         $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
    }
    return $p;
}

$set = explode(' ', 'a b c');

// $all will contain the final output
$all = $set;
while(count($set) > 1) {
    $perms = array();
    $size = count($set) - 1;
    $perm = range(0, $size);
    $j = 0;

    do { 
         foreach ($perm as $i) { $perms[$j][] = $set[$i]; }
    } while ($perm = pc_next_permutation($perm, $size) and ++$j);

    foreach ($perms as $p) {
         $all[] = implode(' ', $p);
    }
    array_pop($set);    
}

// display results
foreach($all as $each) {
    echo $each . "\n";
}

输出

a
b
c
a b c
a c b
b a c
b c a
c a b
c b a
a b
b a

活生生的例子

于 2012-05-20T21:54:58.677 回答