web-dev-qa-db-fra.com

Comment générer toutes les permutations d'une chaîne en PHP?

J'ai besoin d'un algorithme qui renvoie toutes les combinaisons possibles de tous les caractères dans une chaîne.

J'ai essayé:

$langd = strlen($input);
 for($i = 0;$i < $langd; $i++){
     $tempStrang = NULL;
     $tempStrang .= substr($input, $i, 1);
  for($j = $i+1, $k=0; $k < $langd; $k++, $j++){
   if($j > $langd) $j = 0;
   $tempStrang .= substr($input, $j, 1);
 }
 $myarray[] = $tempStrang;
}

Mais cela ne renvoie que la même combinaison de montant que la longueur de la chaîne.

Dit le $input = "hey", le résultat serait: hey, hye, eyh, ehy, yhe, yeh.

40
Johan

Vous pouvez utiliser une approche basée sur le back tracking pour générer systématiquement toutes les permutations:

// function to generate and print all N! permutations of $str. (N = strlen($str)).
function permute($str,$i,$n) {
   if ($i == $n)
       print "$str\n";
   else {
        for ($j = $i; $j < $n; $j++) {
          swap($str,$i,$j);
          permute($str, $i+1, $n);
          swap($str,$i,$j); // backtrack.
       }
   }
}

// function to swap the char at pos $i and $j of $str.
function swap(&$str,$i,$j) {
    $temp = $str[$i];
    $str[$i] = $str[$j];
    $str[$j] = $temp;
}   

$str = "hey";
permute($str,0,strlen($str)); // call the function.

Production:

#php a.php
hey
hye
ehy
eyh
yeh
yhe
51
codaddict

Ma variante (fonctionne également avec l'entrée de tableau ou de chaîne)

function permute($arg) {
    $array = is_string($arg) ? str_split($arg) : $arg;
    if(1 === count($array))
        return $array;
    $result = array();
    foreach($array as $key => $item)
        foreach(permute(array_diff_key($array, array($key => $item))) as $p)
            $result[] = $item . $p;
    return $result;
}

P.S.: Downvoter, veuillez expliquer votre position. Ce code utilise str_split et array_diff_key fonctions standard, mais cet extrait de code est le le plus petit, il implémente pur récursivité de la queue avec un seul paramètre d'entrée et il est isomorphe au type de données d'entrée.

Peut-être qu'il perdra un peu les repères lors de la comparaison avec d'autres implémentations (mais les performances sont en fait presque les mêmes que dans la réponse de @ codaddict pour plusieurs chaînes de caractères), mais pourquoi nous ne pouvons pas simplement le considérer comme l'une des différentes alternatives qui a son ses propres avantages?

26
zavg

Je mettrais tous les caractères dans un tableau et j'écrirais une fonction récursive qui "rayerait" tous les caractères restants. Si le tableau est vide, vers un tableau de référence passé.

<?php

$input = "hey";

function string_getpermutations($prefix, $characters, &$permutations)
{
    if (count($characters) == 1)
        $permutations[] = $prefix . array_pop($characters);
    else
    {
        for ($i = 0; $i < count($characters); $i++)
        {
            $tmp = $characters;
            unset($tmp[$i]);

            string_getpermutations($prefix . $characters[$i], array_values($tmp), $permutations);
        }
    }
}
$characters = array();
for ($i = 0; $i < strlen($input); $i++)
    $characters[] = $input[$i];
$permutations = array();

print_r($characters);
string_getpermutations("", $characters, $permutations);

print_r($permutations);

Imprime:

Array
(
    [0] => h
    [1] => e
    [2] => y
)
Array
(
    [0] => hey
    [1] => hye
    [2] => ehy
    [3] => eyh
    [4] => yhe
    [5] => yeh
)

Ah oui, les combinaisons = l'ordre n'ont pas d'importance. permutations = l'ordre importe.

Alors hé, hye yeh sont tous la même combinaison, mais 3 permutations distinctes comme mentionné. Attention, l'échelle des articles augmente très rapidement. Cela s'appelle factoriel et s'écrit comme 6! = 6 * 5 * 4 * 3 * 2 * 1 = 720 éléments (pour une chaîne de 6 caractères). Une chaîne de 10 caractères sera 10! = 3628800 permutations déjà, ce qui est un très grand tableau. Dans cet exemple, c'est 3! = 3 * 2 * 1 = 6.

7
Hans

Mon approche utilise la récursivité et aucune boucle, veuillez vérifier et donner votre avis:

function permute($str,$index=0,$count=0)
{
    if($count == strlen($str)-$index)
        return;

    $str = rotate($str,$index);

    if($index==strlen($str)-2)//reached to the end, print it
    {
        echo $str."<br> ";//or keep it in an array
    }

    permute($str,$index+1);//rotate its children

    permute($str,$index,$count+1);//rotate itself
}

function rotate($str,$index)
{
    $tmp = $str[$index];
    $i=$index;
    for($i=$index+1;$i<strlen($str);$i++)
    {
        $str[$i-1] = $str[$i];
    }
    $str[$i-1] = $tmp;
    return $str;
}
permute("hey");
1
Gaurav Pandey