如何使用PHP获取所有可能的字符串排列?

时间:2011-07-31 19:43:05

标签: php combinatorics

有一个字符映射,如下所示:

$replacements = array(
    array('a', 'b'), // a => b
    array('a', 'c'), // a => c
    array('b', 'n'),
    array('c', 'x'),
);

还有一个输入字符串,比如说“cbaa”。如何获得所有组合,其中至少有一个字符被替换为其中一个替换字符?在这个例子中,“a”可以替换为“b”和“c”,因此字符串包括:

xbaa
cnaa
xbba
cbca
cbab
cbac
...
xnaa
xnac
...

4 个答案:

答案 0 :(得分:2)

$replacements = array(
    array('a', 'b'), // a => b
    array('a', 'c'), // a => c
    array('b', 'n'),
    array('c', 'x'),
);

$str = 'cbaa';

// lets change replacements format
$replacementsSorted = array();
foreach ($replacements as $pair) {
   if (isset($replacementsSorted[$pair[0]])) {
      $replacementsSorted[$pair[0]][] = $pair[1];
   } else {
      $replacementsSorted[$pair[0]] = array($pair[1]);
   }
}

$replacements = $replacementsSorted;

class Combine {
   private static $_result = array();

   static function run($str, $replacements, $start) {
      self::$_result[] = $str;
      $l = strlen($str);
      for ($i = $start; $i < $l; $i++) {      
         if (isset($replacements[$str[$i]])) {
            foreach ($replacements[$str[$i]] as $key => $val) {
               $str[$i] = $val;
               if (in_array($str, self::$_result)) {
                  continue;
               }
               // call recursion
               self::run($str, $replacements, $i+1);
            }
         }
      }
      return self::$_result;
   }
}

var_dump( Combine::run($str, $replacements, 0) );

答案 1 :(得分:2)

以下是Dmitry Tarasov代码的修改版本(请给他所有信用),这似乎正常。

class Combine {
    private static $_result = array();

    public static function run($str, $replacements){
        self::_run($str, $replacements, 0);
        return array_values(array_unique(self::$_result));
    }

    private static function _run($str, $replacements, $start){
        self::$_result[] = $str;
        for($i = $start, $l = strlen($str); $i < $l; $i++){ 
            self::_run($str, $replacements, $i+1);    
            if(isset($replacements[$str[$i]])){
                foreach($replacements[$str[$i]] as $key => $val){
                    $str[$i] = $val;
                    // call recursion
                    self::_run($str, $replacements, $i+1);
                }
            }
        }
    }
}

print_r( Combine::run($str, $replacements) );

引入私有函数是为了避免重复执行多次繁重的数组操作,而不是在root调用的任何地方使用它们。

答案 2 :(得分:0)

function combi($str, $replac, &$result, $builtstr="", $pos=0) {
    $len = strlen($str);
    if ($pos == $len) {
        if ($builtstr != $str)
            $result[] = $builtstr;
        return;
    }
    $c = $str[$pos];
    $poss = array();
    $poss[] = $c;
    foreach($replac as $v) {
        if ($v[0] == $c)
            $poss[] = $v[1];
    }
    foreach($poss as $k=>$c_repl) {
        combi($str, $replac, $result, $builtstr . $c_repl, $pos+1);
    }
}

$combinations = array();
combi("cbaa", $replacements, $combinations);

答案 3 :(得分:0)

<?php
error_reporting(E_ALL | E_STRICT);
$replacements = array(
array('a', 'b'), // a => b
array('a', 'c'), // a => c
array('b', 'n'),
array('c', 'x'),
);

$inputstr = "cbaa";

$hash = array(); // hash map maps originals characters with an array of the original character and the other replacements
foreach ($replacements as $pair) {
  if (!isset($hash[$pair[0]])) { $hash[$pair[0]] = array($pair[0]); }
  $hash[$pair[0]][] = $pair[1];
}

echo "hash:\n";
print_r($hash);

$to_flat = array_map(function($c) use ($hash) { // maps original input string characters to an array of candidates
  return $hash[$c];
}, str_split($inputstr));

echo "to_flat:\n";
print_r($to_flat);

$perms = array_reduce($to_flat, function($akku, $letter_targets){
  $theseperms = array();
  foreach ($akku as $work) { // for each permutation made
    foreach ($letter_targets as $target) { // for each character candidate
      $newakku = $work;
      $newakku .= $target;
      $theseperms[] = $newakku;
    }
  }
  return $theseperms;
}, array(""));

unset($perms[array_search($inputstr, $perms, true)]); //remove cbaa
$perms = array_values($perms); //reset keys

echo "perms:\n";
print_r($perms);
?>