PHP bir dize tüm permütasyon üretmek nasıl?

5 Cevap php

Ben bir dize tüm karakterlerin tüm olası kombinasyon dönmek bir algoritma gerekir.

Ben denedim:

$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;
}

Ama bu sadece dize uzunluğu aynı miktarda kombinasyonu döndürür.

Say $input = "hey", sonuç olacaktır: hey, hye, eyh, ehy, yhe, yeh.

5 Cevap

Sen sistematik tüm permütasyon oluşturmak için bir geri izleme tabanlı bir yaklaşım kullanabilirsiniz:

// 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.

Çıktı:

#php a.php
hey
hye
ehy
eyh
yeh
yhe

Ben bir dizideki tüm karakterleri koymak ve kalan tüm karakterleri 'out şerit' bir özyinelemeli fonksiyon yazmak istiyorum. Dizi bir referans geçti dizi, boş ise.

<?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);

Çıkış yazdırır:

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

Ah yes, combinations = order doens't matter. permutations = order does matter.

Yani, hey, hye yeh hepsi aynı kombinasyonu olan, ancak söz konusu 3 ayrı permütasyon gibi. Öğelerin ölçek çok hızlı gider dikkat edin. Bu faktöryel denir ve 6 gibi yazılır! (6 karakter dizesi için) = 6 * 5 * 4 * 3 * 2 * 1 = 720 ürün. A 10 karakter dizesi 10 olacak! = Çok büyük bir dizidir zaten 3628800 permütasyon,. Bu örnekte 3 var! = 3 * = 6 2 * 1.

Benim varyant (dizi veya dize girişi ile de çalışır)

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, konumunu açıklayınız. Bu kod, ek str_split ve array_diff_key standart fonksiyonları kullanır, ancak bu kod parçacığını smallest, sadece tek bir giriş ile tail recursion saf uygular olduğunu parametre ve isomorphic giriş veri türü olduğunu.

Diğer uygulamaları ile karşılaştırırken bu kriterler biraz kaybedersiniz (ama performans aslında birkaç karakter dizeleri için cevap codaddict @ gibi hemen hemen aynıdır) olabilir, ama neden biz sadece vardır, farklı alternatiflerden biri olarak düşünebilirsiniz cann't onun kendi avantajları?

Bu tipik bir backtracking sorun olduğunu söyleyebilirim.

Ben böyle bir iş yapmak için bir sınıf yazdım, ben bütün kombinasyonları saklanması gibi Iterator interface eğlenceli ve bu konu için çok yararlı, bazı bruteforce tarzı iş için (yapıyorsun bellek vadede zor olabilir bulundu test amaçlı, tabii ki).

class Permute implements Iterator
{

   private $base;
   private $count;
   private $current;

   public function __construct($base)
   {
      $this->base = str_split($base);
      $this->count = count($this->base);
      $this->current = reset($this->base);
   }

   public function current()
   {
      return $this->current;
   }

   public function key()
   {
      return null;
   }

   public function next()
   {
      for ($it = strlen($this->current) - 1; $it >= 0; $it--)
      {
         $pos = array_search($this->current[$it], $this->base);
         if ($pos < ($this->count - 1))
         {
            $this->current[$it] = $this->base[$pos + 1];
            for ($i = $it + 1; $i < strlen($this->current); $i++)
            {
               $this->current[$i] = reset($this->base);
            }
            break ;
         }
      }
      if ($it == -1)
      {
         $this->current = str_repeat(reset($this->base), strlen($this->current) + 1);
      }
   }

   public function rewind()
   {
      $this->cur = reset($this->base);
   }

   public function valid()
   {
      return true;
   }

}

Demo:

$permute = new Permute("ABCD");
foreach ($permute as $test)
{
   echo $test . PHP_EOL;
   if (strlen($test) == 4)
   {
      break;
   }
}

Sonuç:

A B C D AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD AAA AAB AAC AAD ABA ABB ABC ABD ACA ACB ACC ACD ADA ADB ADC ADD BAA BAB BAC BAD BBA BBB BBC BBD BCA BCB BCC BCD BDA BDB BDC BDD CAA CAB CAC CAD CBA CBB CBC CBD CCA CCB CCC CCD CDA CDB CDC CDD DAA DAB DAC DAD DBA DBB DBC DBD DCA DCB DCC DCD DDA DDB DDC DDD AAAA