Algoritmo para gerar todas as permutações possíveis de uma lista?

119

Digamos que eu tenha uma lista de n elementos, eu sei que existem n! maneiras possíveis de solicitar esses elementos. O que é um algoritmo para gerar todos os pedidos possíveis desta lista? Exemplo, eu tenho a lista [a, b, c]. O algoritmo retornaria [[a, b, c], [a, c, b,], [b, a, c], [b, c, a], [c, a, b], [c, b , uma]].

Estou lendo isso aqui http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations

Mas a Wikipedia nunca foi boa em explicar. Eu não entendo muito disso.

fent
fonte
5
Eu escrevi uma resposta extensa para outra pergunta sobre gerar permutações uma vez. Eu acho que vai ser do seu interesse: stackoverflow.com/questions/1506078/…
Joren
2
Isso pode resolver o seu problema en.wikipedia.org/wiki/Heap's_algorithm
Felix

Respostas:

96

Basicamente, para cada item da esquerda para a direita, todas as permutações dos itens restantes são geradas (e cada uma é adicionada com os elementos atuais). Isso pode ser feito recursivamente (ou iterativamente, se você gosta de dor) até que o último item seja atingido, momento em que existe apenas um pedido possível.

Portanto, com a lista [1,2,3,4], todas as permutações que começam com 1 são geradas, depois todas as permutações que começam com 2, depois 3 e 4.

Isso reduz efetivamente o problema de encontrar permutações de uma lista de quatro itens para uma lista de três itens. Após reduzir para 2 e, em seguida, 1 lista de itens, todos eles serão encontrados.
Exemplo mostrando permutações de processo usando três esferas coloridas:
Bolas coloridas de vermelho, verde e azul pediram permutações(de https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki/File:Permutations_RGB. svg )

WhirlWind
fonte
2
Também pensei sobre isso no começo, mas o elemento atual não seria colocado entre alguns dos itens a seguir. Portanto, nem todas as permutações seriam geradas.
fent 26/04/10
@LLer desculpe, atualizei minha resposta de "seguindo" para "restante" para esclarecer. Mas funciona bem. Verifique escrevendo o código e verificando se você recebe 4! resultados diferentes.
turbilhão
2
int permutações (int n, vetor <int> a) {static int num_permutations = 0; if (n == (a.size () - 1)) {for (int i = 0; i <a.size (); i ++) cout << a [i] << ""; cout << "\ n"; num_permutations ++; } else {for (int i = n + 1; i <= a.size (); i ++) {permutações (n + 1, a); if (i <a.size ()) int temp = a [n], a [n] = a [i], a [i] = temp; }} retornar num_permutations; } int main (vazio) {vetor <int> v; v.push_back (1); ... permutações de retorno (0, v); }
Somesh 4/11/14
Ops - não sei como formatar o código em um comentário ... Testei o código com 7 e obtive 5040. Agradecemos a @WhirlWind pela sugestão.
Somesh
esse algo não muda se você pode ter 2 ou 3 bolas vermelhas nº 1, em vez de apenas 1 de cada cor?
Alexander Mills
26

Aqui está um algoritmo em Python que funciona no local em uma matriz:

def permute(xs, low=0):
    if low + 1 >= len(xs):
        yield xs
    else:
        for p in permute(xs, low + 1):
            yield p        
        for i in range(low + 1, len(xs)):        
            xs[low], xs[i] = xs[i], xs[low]
            for p in permute(xs, low + 1):
                yield p        
            xs[low], xs[i] = xs[i], xs[low]

for p in permute([1, 2, 3, 4]):
    print p

Você pode experimentar o código por si mesmo aqui: http://repl.it/J9v

cdiggins
fonte
Você pode explicar a parte do rendimento? Não consegui executar o código a seco. Desde já, obrigado.
Agniswar Bakshi
A pergunta Stack Overflow em stackoverflow.com/questions/104420/… afirma que existe um módulo de biblioteca padrão nas versões 2.6 em diante e tem uma resposta que fornece uma solução de 6 linhas em uma função para obter permutações de lista.
Edward
@Agniswar À primeira vista, a declaração de rendimento é usada para definir geradores, substituindo o retorno de uma função para fornecer um resultado ao seu chamador sem destruir as variáveis ​​locais. Diferentemente de uma função, onde em cada chamada começa com um novo conjunto de variáveis, um gerador retoma a execução de onde foi interrompida. pythoncentral.io/python-generators-and-yield-keyword
MSS
Esta solução não funcionará ao lidar com uma lista de entradas idênticas.
KaiserKatze #
Obrigado por compartilhar. Isso é intuitivo e eficiente, embora a saída não esteja em ordem lexicográfica.
27419 Sam
16

Já existem muitas soluções boas aqui, mas eu gostaria de compartilhar como resolvi esse problema sozinho e espero que isso possa ser útil para alguém que também gostaria de obter sua própria solução.

Depois de refletir sobre o problema, cheguei a duas conclusões a seguir:

  1. Para a lista Lde tamanho n, haverá um número igual de soluções começando com L 1 , L 2 ... L n da lista. Como no total existem n!permutações da lista de tamanho n, obtemos n! / n = (n-1)!permutações em cada grupo.
  2. A lista de 2 elementos possui apenas 2 permutações => [a,b]e [b,a].

Usando essas duas idéias simples, derivamos o seguinte algoritmo:

permute array
    if array is of size 2
       return first and second element as new array
       return second and first element as new array
    else
        for each element in array
            new subarray = array with excluded element
            return element + permute subarray

Aqui está como eu implementei isso em c #:

public IEnumerable<List<T>> Permutate<T>(List<T> input)
{
    if (input.Count == 2) // this are permutations of array of size 2
    {
        yield return new List<T>(input);
        yield return new List<T> {input[1], input[0]}; 
    }
    else
    {
        foreach(T elem in input) // going through array
        {
            var rlist = new List<T>(input); // creating subarray = array
            rlist.Remove(elem); // removing element
            foreach(List<T> retlist in Permutate(rlist))
            {
                retlist.Insert(0,elem); // inserting the element at pos 0
                yield return retlist;
            }

        }
    }
}
Alexander Galkin
fonte
16

A resposta da Wikipedia para "ordem lexicográfica" parece perfeitamente explícita no estilo de um livro de receitas para mim. Ele cita uma origem do século XIV para o algoritmo!

Acabei de escrever uma rápida implementação em Java do algoritmo da Wikipedia como uma verificação e não foi problema. Mas o que você tem no seu Q como exemplo NÃO é "listar todas as permutações", mas "uma LISTA de todas as permutações", portanto, a Wikipedia não será de grande ajuda para você. Você precisa de um idioma no qual as listas de permutações sejam construídas de maneira viável. E acredite, listas de alguns bilhões de comprimento geralmente não são tratadas em idiomas imperativos. Você realmente deseja que uma linguagem de programação funcional não estrita, na qual as listas sejam um objeto de primeira classe, apareça, sem aproximar a máquina da morte por calor do Universo.

Isso é fácil. No Haskell padrão ou em qualquer linguagem FP moderna:

-- perms of a list
perms :: [a] -> [ [a] ]
perms (a:as) = [bs ++ a:cs | perm <- perms as, (bs,cs) <- splits perm]
perms []     = [ [] ]

e

-- ways of splitting a list into two parts
splits :: [a] -> [ ([a],[a]) ]
splits []     = [ ([],[]) ]
splits (a:as) = ([],a:as) : [(a:bs,cs) | (bs,cs) <- splits as]
Peter Breuer
fonte
9

Como o WhirlWind disse, você começa do começo.

Você troca o cursor com cada valor restante, incluindo o próprio cursor, todas essas são instâncias novas (usei um int[]e array.clone()no exemplo).

Em seguida, execute permutações em todas essas listas diferentes, certificando-se de que o cursor esteja à direita.

Quando não houver mais valores restantes (o cursor está no final), imprima a lista. Esta é a condição de parada.

public void permutate(int[] list, int pointer) {
    if (pointer == list.length) {
        //stop-condition: print or process number
        return;
    }
    for (int i = pointer; i < list.length; i++) {
        int[] permutation = (int[])list.clone();.
        permutation[pointer] = list[i];
        permutation[i] = list[pointer];
        permutate(permutation, pointer + 1);
    }
}
dinadineke
fonte
8

A recursiva sempre exige algum esforço mental para manter. E para grandes números, o fatorial é facilmente enorme e o excesso de pilha será facilmente um problema.

Para números pequenos (3 ou 4, o que é encontrado principalmente), vários loops são bastante simples e diretos. É lamentável que as respostas com loops não tenham sido votadas.

Vamos começar com enumeração (em vez de permutação). Basta ler o código como código pseudo-perl.

$foreach $i1 in @list
    $foreach $i2 in @list 
        $foreach $i3 in @list
            print "$i1, $i2, $i3\n"

A enumeração é mais frequentemente encontrada do que a permutação, mas se ela for necessária, basta adicionar as condições:

$foreach $i1 in @list
    $foreach $i2 in @list 
        $if $i2==$i1
            next
        $foreach $i3 in @list
            $if $i3==$i1 or $i3==$i2
                next
            print "$i1, $i2, $i3\n"

Agora, se você realmente precisa de um método geral potencialmente para grandes listas, podemos usar o método radix. Primeiro, considere o problema de enumeração:

$n=@list
my @radix
$for $i=0:$n
    $radix[$i]=0
$while 1
    my @temp
    $for $i=0:$n
        push @temp, $list[$radix[$i]]
    print join(", ", @temp), "\n"
    $call radix_increment

subcode: radix_increment
    $i=0
    $while 1
        $radix[$i]++
        $if $radix[$i]==$n
            $radix[$i]=0
            $i++
        $else
            last
    $if $i>=$n
        last

O incremento de base é essencialmente a contagem de números (na base do número de elementos da lista).

Agora, se você precisar de permissão, basta adicionar as verificações dentro do loop:

subcode: check_permutation
    my @check
    my $flag_dup=0
    $for $i=0:$n
        $check[$radix[$i]]++
        $if $check[$radix[$i]]>1
            $flag_dup=1
            last
    $if $flag_dup
        next

Edit: O código acima deve funcionar, mas para permutação, radix_increment pode ser um desperdício. Portanto, se o tempo é uma preocupação prática, temos que mudar radix_increment para permute_inc:

subcode: permute_init
    $for $i=0:$n
        $radix[$i]=$i

subcode: permute_inc                                       
    $max=-1                                                
    $for $i=$n:0                                           
        $if $max<$radix[$i]                                
            $max=$radix[$i]                                
        $else                                              
            $for $j=$n:0                                   
                $if $radix[$j]>$radix[$i]                  
                    $call swap, $radix[$i], $radix[$j]     
                    break                                  
            $j=$i+1                                        
            $k=$n-1                                        
            $while $j<$k                                   
                $call swap, $radix[$j], $radix[$k]         
                $j++                                       
                $k--                                       
            break                                          
    $if $i<0                                               
        break                                              

Claro que agora esse código é logicamente mais complexo, deixarei para o exercício do leitor.

Hui Zhou
fonte
7

insira a descrição da imagem aqui

// C program to print all permutations with duplicates allowed
#include <stdio.h>
#include <string.h>

/* Function to swap values at two pointers */
void swap(char *x, char *y)
{
    char temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

/* Function to print permutations of string
   This function takes three parameters:
   1. String
   2. Starting index of the string
   3. Ending index of the string. */

void permute(char *a, int l, int r)
{
   int i;
   if (l == r)
     printf("%s\n", a);
   else
   {
       for (i = l; i <= r; i++)
       {
          swap((a+l), (a+i));
          permute(a, l+1, r);
          swap((a+l), (a+i)); //backtrack
       }
   }
}

/* Driver program to test above functions */
int main()
{
    char str[] = "ABC";
    int n = strlen(str);
    permute(str, 0, n-1);
    return 0;
}

Referência: Geeksforgeeks.org

Sazzad Hissain Khan
fonte
5

Se alguém se perguntar como fazer permutação em javascript.

Ideia / pseudocódigo

  1. escolha um elemento de cada vez
  2. permute o restante do elemento e adicione o elemento selecionado a toda a permutação

por exemplo. 'a' + permuto (bc). permuto de bc seria bc & cb. Agora adicione estes dois dará abc, acb. da mesma forma, escolha b + permute (ac) provará bac, bca ... e continuará.

agora olhe o código

function permutations(arr){

   var len = arr.length, 
       perms = [],
       rest,
       picked,
       restPerms,
       next;

    //for one or less item there is only one permutation 
    if (len <= 1)
        return [arr];

    for (var i=0; i<len; i++)
    {
        //copy original array to avoid changing it while picking elements
        rest = Object.create(arr);

        //splice removed element change array original array(copied array)
        //[1,2,3,4].splice(2,1) will return [3] and remaining array = [1,2,4]
        picked = rest.splice(i, 1);

        //get the permutation of the rest of the elements
        restPerms = permutations(rest);

       // Now concat like a+permute(bc) for each
       for (var j=0; j<restPerms.length; j++)
       {
           next = picked.concat(restPerms[j]);
           perms.push(next);
       }
    }

   return perms;
}

Tome seu tempo para entender isso. Eu recebi esse código de ( pertumation em JavaScript )

Jhankar Mahbub
fonte
Eu estava pensando em algo semelhante, mas você não deveria adicionar o elemento escolhido na frente e no final dos restParams? Nesse caso, para 'abc', se você escolher a, as permutações 'bc' serão 'bc' e 'cb'. Quando você adiciona 'a' de volta à lista, não deve adicioná-lo à frente como 'a + bc' + 'a + cb', mas também no final como 'bc + a' + 'cb + a' de a lista?
Artimus
Você obterá essas permutações quando começar com 'b' e 'c', respectivamente. (ou seja, a segunda e terceira execuções do loop externo 'for')
Ryan O'Neill
3

Outro em Python, não está no lugar do @ cdiggins, mas acho que é mais fácil entender

def permute(num):
    if len(num) == 2:
        # get the permutations of the last 2 numbers by swapping them
        yield num
        num[0], num[1] = num[1], num[0]
        yield num
    else:
        for i in range(0, len(num)):
            # fix the first number and get the permutations of the rest of numbers
            for perm in permute(num[0:i] + num[i+1:len(num)]):
                yield [num[i]] + perm

for p in permute([1, 2, 3, 4]):
    print p
zhywu
fonte
3

Eu estava pensando em escrever um código para obter as permutações de qualquer número inteiro de qualquer tamanho, ou seja, fornecendo um número 4567, obteremos todas as permutações possíveis até 7654 ... Então trabalhei nele e encontrei um algoritmo e finalmente o implementei. é o código escrito em "c". Você pode simplesmente copiá-lo e executar em qualquer compilador de código aberto. Mas algumas falhas estão esperando para serem depuradas. Por favor aprecie.

Código:

#include <stdio.h>
#include <conio.h>
#include <malloc.h>

                //PROTOTYPES

int fact(int);                  //For finding the factorial
void swap(int*,int*);           //Swapping 2 given numbers
void sort(int*,int);            //Sorting the list from the specified path
int imax(int*,int,int);         //Finding the value of imax
int jsmall(int*,int);           //Gives position of element greater than ith but smaller than rest (ahead of imax)
void perm();                    //All the important tasks are done in this function


int n;                         //Global variable for input OR number of digits

void main()
{
int c=0;

printf("Enter the number : ");
scanf("%d",&c);
perm(c);
getch();
}

void perm(int c){
int *p;                     //Pointer for allocating separate memory to every single entered digit like arrays
int i, d;               
int sum=0;
int j, k;
long f;

n = 0;

while(c != 0)               //this one is for calculating the number of digits in the entered number
{
    sum = (sum * 10) + (c % 10);
    n++;                            //as i told at the start of loop
    c = c / 10;
}

f = fact(n);                        //It gives the factorial value of any number

p = (int*) malloc(n*sizeof(int));                //Dynamically allocation of array of n elements

for(i=0; sum != 0 ; i++)
{
    *(p+i) = sum % 10;                               //Giving values in dynamic array like 1234....n separately
    sum = sum / 10;
}

sort(p,-1);                                         //For sorting the dynamic array "p"

for(c=0 ; c<f/2 ; c++) {                        //Most important loop which prints 2 numbers per loop, so it goes upto 1/2 of fact(n)

    for(k=0 ; k<n ; k++)
        printf("%d",p[k]);                       //Loop for printing one of permutations
    printf("\n");

    i = d = 0;
    i = imax(p,i,d);                            //provides the max i as per algo (i am restricted to this only)
    j = i;
    j = jsmall(p,j);                            //provides smallest i val as per algo
    swap(&p[i],&p[j]);

    for(k=0 ; k<n ; k++)
        printf("%d",p[k]);
    printf("\n");

    i = d = 0;
    i = imax(p,i,d);
    j = i;
    j = jsmall(p,j);
    swap(&p[i],&p[j]);

    sort(p,i);
}
free(p);                                        //Deallocating memory
}

int fact (int a)
{
long f=1;
while(a!=0)
{
    f = f*a;
    a--;
}
return f;
}


void swap(int *p1,int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
return;
}


void sort(int*p,int t)
{
int i,temp,j;
for(i=t+1 ; i<n-1 ; i++)
{
    for(j=i+1 ; j<n ; j++)
    {
        if(*(p+i) > *(p+j))
        {
            temp = *(p+i);
            *(p+i) = *(p+j);
            *(p+j) = temp;
        }
    }
}
}


int imax(int *p, int i , int d)
{
    while(i<n-1 && d<n-1)
{
    if(*(p+d) < *(p+d+1))
    {   
        i = d;
        d++;
    }
    else
        d++;
}
return i;
}


int jsmall(int *p, int j)
{
int i,small = 32767,k = j;
for (i=j+1 ; i<n ; i++)
{
    if (p[i]<small && p[i]>p[k])
    {     
       small = p[i];
       j = i;
    }
}
return j;
}
FreakPirate
fonte
3
void permutate(char[] x, int i, int n){
    x=x.clone();
    if (i==n){
        System.out.print(x);
        System.out.print(" ");
        counter++;}
    else
    {
        for (int j=i; j<=n;j++){
     //   System.out.print(temp); System.out.print(" ");    //Debugger
        swap (x,i,j);
      //  System.out.print(temp); System.out.print(" "+"i="+i+" j="+j+"\n");// Debugger
        permutate(x,i+1,n);
    //    swap (temp,i,j);
    }
    }
}

void swap (char[] x, int a, int b){
char temp = x[a];
x[a]=x[b];
x[b]=temp;
}

Eu criei este. com base em pesquisas muito permutadas (qwe, 0, qwe.length-1); Só para você saber, você pode fazê-lo com ou sem retorno

Luigi Mackenzie C. Brito
fonte
3

Aqui está um método Ruby de brinquedo que funciona assim #permutation.to_apode ser mais legível para pessoas loucas. É hella lento, mas também 5 linhas.

def permute(ary)
  return [ary] if ary.size <= 1
  ary.collect_concat.with_index do |e, i|
    rest = ary.dup.tap {|a| a.delete_at(i) }
    permute(rest).collect {|a| a.unshift(e) }
  end
end
Jenner La Fave
fonte
3

Eu escrevi essa solução recursiva em ANSI C. Cada execução da função Permutate fornece uma permutação diferente até que todas sejam concluídas. Variáveis ​​globais também podem ser usadas para variáveis ​​fact e count.

#include <stdio.h>
#define SIZE 4

void Rotate(int vec[], int size)
{
    int i, j, first;

    first = vec[0];
    for(j = 0, i = 1; i < size; i++, j++)
    {
        vec[j] = vec[i];
    }
    vec[j] = first;
}

int Permutate(int *start, int size, int *count)
{
    static int fact;

    if(size > 1)
    {
        if(Permutate(start + 1, size - 1, count))
        {
            Rotate(start, size);
        }
        fact *= size;
    }
    else
    {
        (*count)++;
        fact = 1;
    }

    return !(*count % fact);
}

void Show(int vec[], int size)
{
    int i;

    printf("%d", vec[0]);
    for(i = 1; i < size; i++)
    {
        printf(" %d", vec[i]);
    }
    putchar('\n');
}

int main()
{
    int vec[] = { 1, 2, 3, 4, 5, 6 }; /* Only the first SIZE items will be permutated */
    int count = 0;

    do
    {
        Show(vec, SIZE);
    } while(!Permutate(vec, SIZE, &count));

    putchar('\n');
    Show(vec, SIZE);
    printf("\nCount: %d\n\n", count);

    return 0;
}
Horacio
fonte
3

Versão Java

/**
 * @param uniqueList
 * @param permutationSize
 * @param permutation
 * @param only            Only show the permutation of permutationSize,
 *                        else show all permutation of less than or equal to permutationSize.
 */
public static void my_permutationOf(List<Integer> uniqueList, int permutationSize, List<Integer> permutation, boolean only) {
    if (permutation == null) {
        assert 0 < permutationSize && permutationSize <= uniqueList.size();
        permutation = new ArrayList<>(permutationSize);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
    }
    for (int i : uniqueList) {
        if (permutation.contains(i)) {
            continue;
        }
        permutation.add(i);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        } else if (permutation.size() == permutationSize) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
        if (permutation.size() < permutationSize) {
            my_permutationOf(uniqueList, permutationSize, permutation, only);
        }
        permutation.remove(permutation.size() - 1);
    }
}

Por exemplo

public static void main(String[] args) throws Exception { 
    my_permutationOf(new ArrayList<Integer>() {
        {
            add(1);
            add(2);
            add(3);

        }
    }, 3, null, true);
}

resultado:

  [1, 2, 3]
  [1, 3, 2]
  [2, 1, 3]
  [2, 3, 1]
  [3, 1, 2]
  [3, 2, 1]
Bruce Zu
fonte
3

em PHP

$set=array('A','B','C','D');

function permutate($set) {
    $b=array();
    foreach($set as $key=>$value) {
        if(count($set)==1) {
            $b[]=$set[$key];
        }
        else {
            $subset=$set;
            unset($subset[$key]);
            $x=permutate($subset);
            foreach($x as $key1=>$value1) {
                $b[]=$value.' '.$value1;
            }
        }
    }
    return $b;
}

$x=permutate($set);
var_export($x);
nerdface
fonte
3

Aqui está o código em Python para imprimir todas as permutações possíveis de uma lista:

def next_perm(arr):
    # Find non-increasing suffix
    i = len(arr) - 1
    while i > 0 and arr[i - 1] >= arr[i]:
        i -= 1
    if i <= 0:
        return False

    # Find successor to pivot
    j = len(arr) - 1
    while arr[j] <= arr[i - 1]:
        j -= 1
    arr[i - 1], arr[j] = arr[j], arr[i - 1]

    # Reverse suffix
    arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
    print arr
    return True

def all_perm(arr):
    a = next_perm(arr)
    while a:
        a = next_perm(arr)
    arr = raw_input()
    arr.split(' ')
    arr = map(int, arr)
    arr.sort()
    print arr
    all_perm(arr)

Eu usei um algoritmo de ordem lexicográfica para obter todas as permutações possíveis, mas um algoritmo recursivo é mais eficiente. Você pode encontrar o código do algoritmo recursivo aqui: Permutações de recursão do Python

Anuj Mittal
fonte
3
public class PermutationGenerator
{
    private LinkedList<List<int>> _permutationsList;
    public void FindPermutations(List<int> list, int permutationLength)
    {
        _permutationsList = new LinkedList<List<int>>();
        foreach(var value in list)
        {
            CreatePermutations(value, permutationLength);
        }
    }

    private void CreatePermutations(int value, int permutationLength)
    {
        var node = _permutationsList.First;
        var last = _permutationsList.Last;
        while (node != null)
        {
            if (node.Value.Count < permutationLength)
            {
                GeneratePermutations(node.Value, value, permutationLength);
            }
            if (node == last)
            {
                break;
            }
            node = node.Next;
        }

        List<int> permutation = new List<int>();
        permutation.Add(value);
        _permutationsList.AddLast(permutation);
    }

    private void GeneratePermutations(List<int> permutation, int value, int permutationLength)
    {
       if (permutation.Count < permutationLength)
        {
            List<int> copyOfInitialPermutation = new List<int>(permutation);
            copyOfInitialPermutation.Add(value);
            _permutationsList.AddLast(copyOfInitialPermutation);
            List<int> copyOfPermutation = new List<int>();
            copyOfPermutation.AddRange(copyOfInitialPermutation);
            int lastIndex = copyOfInitialPermutation.Count - 1;
            for (int i = lastIndex;i > 0;i--)
            {
                int temp = copyOfPermutation[i - 1];
                copyOfPermutation[i - 1] = copyOfPermutation[i];
                copyOfPermutation[i] = temp;

                List<int> perm = new List<int>();
                perm.AddRange(copyOfPermutation);
                _permutationsList.AddLast(perm);
            }
        }
    }

    public void PrintPermutations(int permutationLength)
    {
        int count = _permutationsList.Where(perm => perm.Count() == permutationLength).Count();
        Console.WriteLine("The number of permutations is " + count);
    }
}
Bahruz Balabayov
fonte
é uma resposta útil #
Ayaz Alifov 17/0218
2

Na cidade Scala

    def permutazione(n: List[Int]): List[List[Int]] = permutationeAcc(n, Nil)



def permutationeAcc(n: List[Int], acc: List[Int]): List[List[Int]] = {

    var result: List[List[Int]] = Nil
    for (i ← n if (!(acc contains (i))))
        if (acc.size == n.size-1)
            result = (i :: acc) :: result
        else
            result = result ::: permutationeAcc(n, i :: acc)
    result
}
Marco
fonte
2

esta é uma versão java para permutação

public class Permutation {

    static void permute(String str) {
        permute(str.toCharArray(), 0, str.length());
    }

    static void permute(char [] str, int low, int high) {
        if (low == high) {
            System.out.println(str);
            return;
        }

        for (int i=low; i<high; i++) {
            swap(str, i, low);
            permute(str, low+1, high);
            swap(str, low, i);
        }

    }

    static void swap(char [] array, int i, int j) {
        char t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
}
杨小勇
fonte
2

Aqui está uma implementação do ColdFusion (requer CF10 devido ao argumento de mesclagem para ArrayAppend ()):

public array function permutateArray(arr){

    if (not isArray(arguments.arr) ) {
        return ['The ARR argument passed to the permutateArray function is not of type array.'];    
    }

    var len = arrayLen(arguments.arr);
    var perms = [];
    var rest = [];
    var restPerms = [];
    var rpLen = 0;
    var next = [];

    //for one or less item there is only one permutation 
    if (len <= 1) {
        return arguments.arr;
    }

    for (var i=1; i <= len; i++) {
        // copy the original array so as not to change it and then remove the picked (current) element
        rest = arraySlice(arguments.arr, 1);
        arrayDeleteAt(rest, i);

         // recursively get the permutation of the rest of the elements
         restPerms = permutateArray(rest);
         rpLen = arrayLen(restPerms);

        // Now concat each permutation to the current (picked) array, and append the concatenated array to the end result
        for (var j=1; j <= rpLen; j++) {
            // for each array returned, we need to make a fresh copy of the picked(current) element array so as to not change the original array
            next = arraySlice(arguments.arr, i, 1);
            arrayAppend(next, restPerms[j], true);
            arrayAppend(perms, next);
        }
     }

    return perms;
}

Baseado na solução js de KhanSharp acima.

earachefl
fonte
Alguma explicação da estratégia geral do seu algoritmo seria uma boa maneira de melhorar essa resposta.
Richard
Então, por que o voto negativo? Esta é uma implementação funcional.
earachefl
@ Richard, a estratégia geral foi explicada acima por Whirlwind e outros. Não vejo o seu comentário sobre todas as outras respostas postadas como implementações sem explicações.
earachefl
1

Sei que isso é muito muito antigo e até fora de tópico no stackoverflow de hoje, mas ainda queria contribuir com uma resposta javascript amigável pela simples razão de que ela é executada no seu navegador.

Também adicionei o debuggerponto de interrupção da diretiva para que você possa percorrer o código (é necessário o cromo) para ver como esse algoritmo funciona. Abra seu console de desenvolvedor no chrome ( F12no Windows ouCMD + OPTION + I no mac) e clique em "Executar trecho de código". Isso implementa o mesmo algoritmo exato que o @WhirlWind apresentou em sua resposta.

Seu navegador deve pausar a execução na debuggerdiretiva. Use F8para continuar a execução do código.

Percorra o código e veja como ele funciona!

function permute(rest, prefix = []) {
  if (rest.length === 0) {
    return [prefix];
  }
  return (rest
    .map((x, index) => {
      const oldRest = rest;
      const oldPrefix = prefix;
      // the `...` destructures the array into single values flattening it
      const newRest = [...rest.slice(0, index), ...rest.slice(index + 1)];
      const newPrefix = [...prefix, x];
      debugger;

      const result = permute(newRest, newPrefix);
      return result;
    })
    // this step flattens the array of arrays returned by calling permute
    .reduce((flattened, arr) => [...flattened, ...arr], [])
  );
}
console.log(permute([1, 2, 3]));

Rico Kahler
fonte
1

Na solução Java a seguir, aproveitamos o fato de que Strings são imutáveis ​​para evitar a clonagem do conjunto de resultados a cada iteração.

A entrada será uma String, digamos "abc", e a saída terá todas as permutações possíveis:

abc
acb
bac
bca
cba
cab

Código:

public static void permute(String s) {
    permute(s, 0);
}

private static void permute(String str, int left){
    if(left == str.length()-1) {
        System.out.println(str);
    } else {
        for(int i = left; i < str.length(); i++) {
            String s = swap(str, left, i);
            permute(s, left+1);
        }
    }
}

private static String swap(String s, int left, int right) {
    if (left == right)
        return s;

    String result = s.substring(0, left);
    result += s.substring(right, right+1);
    result += s.substring(left+1, right);
    result += s.substring(left, left+1);
    result += s.substring(right+1);
    return result;
}

A mesma abordagem pode ser aplicada a matrizes (em vez de uma string):

public static void main(String[] args) {
    int[] abc = {1,2,3};
    permute(abc, 0);
}
public static void permute(int[] arr, int index) {
    if (index == arr.length) {
        System.out.println(Arrays.toString(arr));
    } else {
        for (int i = index; i < arr.length; i++) {
            int[] permutation = arr.clone();
            permutation[index] = arr[i];
            permutation[i] = arr[index];
            permute(permutation, index + 1);
        }
    }
}
Nir Alfasi
fonte
1

É a minha solução em Java:

public class CombinatorialUtils {

    public static void main(String[] args) {
        List<String> alphabet = new ArrayList<>();
        alphabet.add("1");
        alphabet.add("2");
        alphabet.add("3");
        alphabet.add("4");

        for (List<String> strings : permutations(alphabet)) {
            System.out.println(strings);
        }
        System.out.println("-----------");
        for (List<String> strings : combinations(alphabet)) {
            System.out.println(strings);
        }
    }

    public static List<List<String>> combinations(List<String> alphabet) {
        List<List<String>> permutations = permutations(alphabet);
        List<List<String>> combinations = new ArrayList<>(permutations);

        for (int i = alphabet.size(); i > 0; i--) {
            final int n = i;
            combinations.addAll(permutations.stream().map(strings -> strings.subList(0, n)).distinct().collect(Collectors.toList()));
        }
        return combinations;
    }

    public static <T> List<List<T>> permutations(List<T> alphabet) {
        ArrayList<List<T>> permutations = new ArrayList<>();
        if (alphabet.size() == 1) {
            permutations.add(alphabet);
            return permutations;
        } else {
            List<List<T>> subPerm = permutations(alphabet.subList(1, alphabet.size()));
            T addedElem = alphabet.get(0);
            for (int i = 0; i < alphabet.size(); i++) {
                for (List<T> permutation : subPerm) {
                    int index = i;
                    permutations.add(new ArrayList<T>(permutation) {{
                        add(index, addedElem);
                    }});
                }
            }
        }
        return permutations;
    }
}
user2153604
fonte
1

Você realmente não pode falar sobre resolver um problema de permeação em recursão sem postar uma implementação em uma linguagem (dialeta) que foi pioneira na idéia . Portanto, por uma questão de integridade, aqui está uma das maneiras que podem ser feitas no Scheme.

(define (permof wd)
  (cond ((null? wd) '())
        ((null? (cdr wd)) (list wd))
        (else
         (let splice ([l '()] [m (car wd)] [r (cdr wd)])
           (append
            (map (lambda (x) (cons m x)) (permof (append l r)))
            (if (null? r)
                '()
                (splice (cons m l) (car r) (cdr r))))))))

chamando (permof (list "foo" "bar" "baz"))vamos obter:

'(("foo" "bar" "baz")
  ("foo" "baz" "bar")
  ("bar" "foo" "baz")
  ("bar" "baz" "foo")
  ("baz" "bar" "foo")
  ("baz" "foo" "bar"))

Não vou entrar nos detalhes do algoritmo porque já foi explicado o suficiente em outras postagens. A ideia é a mesma.

No entanto, problemas recursivos tendem a ser muito mais difíceis de modelar e pensar em meios destrutivos, como Python, C e Java, enquanto no Lisp ou ML, isso pode ser expresso de forma concisa.

Torta 'Oh' Pah
fonte
0

Aqui está uma solução recursiva em PHP. A publicação do WhirlWind descreve com precisão a lógica. Vale ressaltar que a geração de todas as permutações é executada em tempo fatorial; portanto, pode ser uma boa ideia usar uma abordagem iterativa.

public function permute($sofar, $input){
  for($i=0; $i < strlen($input); $i++){
    $diff = strDiff($input,$input[$i]);
    $next = $sofar.$input[$i]; //next contains a permutation, save it
    $this->permute($next, $diff);
  }
}

A função strDiff usa duas strings, s1e s2, e retorna uma nova string com tudo dentro s1sem elementos em s2(matéria duplicada). Então, strDiff('finish','i')=> 'fnish'(o segundo 'i' não é removido).

Anthony Naddeo
fonte
0

Aqui está um algoritmo no R, caso alguém precise evitar o carregamento de bibliotecas adicionais, como eu precisei.

permutations <- function(n){
    if(n==1){
        return(matrix(1))
    } else {
        sp <- permutations(n-1)
        p <- nrow(sp)
        A <- matrix(nrow=n*p,ncol=n)
        for(i in 1:n){
            A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))
        }
        return(A)
    }
}

Exemplo de uso:

> matrix(letters[permutations(3)],ncol=3)
     [,1] [,2] [,3]
[1,] "a"  "b"  "c" 
[2,] "a"  "c"  "b" 
[3,] "b"  "a"  "c" 
[4,] "b"  "c"  "a" 
[5,] "c"  "a"  "b" 
[6,] "c"  "b"  "a" 
Museful
fonte
0
#!/usr/bin/env python
import time

def permutations(sequence):
  # print sequence
  unit = [1, 2, 1, 2, 1]

  if len(sequence) >= 4:
    for i in range(4, (len(sequence) + 1)):
      unit = ((unit + [i - 1]) * i)[:-1]
      # print unit
    for j in unit:
      temp = sequence[j]
      sequence[j] = sequence[0]
      sequence[0] = temp
      yield sequence
  else:
    print 'You can use PEN and PAPER'


# s = [1,2,3,4,5,6,7,8,9,10]
s = [x for x in 'PYTHON']

print s

z = permutations(s)
try:
  while True:
    # time.sleep(0.0001)
    print next(z)
except StopIteration:
    print 'Done'

['P', 'Y', 'T', 'H', 'O', 'N']
['Y', 'P', 'T', 'H', 'O', 'N']
['T', 'P', 'Y', 'H', 'O', 'N']
['P', 'T', 'Y', 'H', 'O', 'N']
['Y', 'T', 'P', 'H', 'O', 'N']
['T', 'Y', 'P', 'H', 'O', 'N']
['H', 'Y', 'P', 'T', 'O', 'N']
['Y', 'H', 'P', 'T', 'O', 'N']
['P', 'H', 'Y', 'T', 'O', 'N']
['H', 'P', 'Y', 'T', 'O', 'N']
['Y', 'P', 'H', 'T', 'O', 'N']
['P', 'Y', 'H', 'T', 'O', 'N']
['T', 'Y', 'H', 'P', 'O', 'N']
['Y', 'T', 'H', 'P', 'O', 'N']
['H', 'T', 'Y', 'P', 'O', 'N']
['T', 'H', 'Y', 'P', 'O', 'N']
['Y', 'H', 'T', 'P', 'O', 'N']
['H', 'Y', 'T', 'P', 'O', 'N']
['P', 'Y', 'T', 'H', 'O', 'N']
.
.
.
['Y', 'T', 'N', 'H', 'O', 'P']
['N', 'T', 'Y', 'H', 'O', 'P']
['T', 'N', 'Y', 'H', 'O', 'P']
['Y', 'N', 'T', 'H', 'O', 'P']
['N', 'Y', 'T', 'H', 'O', 'P']
mahmoh
fonte
A solução mostra que você não permutou a string conforme o requisito. A segunda permutação deveria ter sido PYTHNO
Rahul Kadukar
0

Este é um código recursivo para java, a idéia é ter um prefixo que adicione o restante dos caracteres:

public static void permutation(String str) { 
    permutation("", str); 
}

private static void permutation(String prefix, String str) {
    int n = str.length();
    if (n == 0) System.out.println(prefix);
    else {
        for (int i = 0; i < n; i++)
            permutation(prefix + str.charAt(i), str);
    }
}

Exemplo:

Entrada = "ABC"; Resultado:

ABC ACB BAC BCA CAB CBA

Rafael Amsili
fonte
1
Boa ideia, mas acho que você também deve remover charAt (i) de strquando chamar recursivamente, caso contrário, ele não será encerrado.
Crystal
1
Para copiar e colar, é necessário (1) atribuir e (2) garantir que as edições estejam corretas. Para atribuição, isso é permitido em introcs.cs.princeton.edu/java/23recursion/… . Sua edição também está incorreta: str.substring (0, i) + str.substring (i + 1, n) não é o mesmo que str, pois o primeiro omite o caractere na posição i.
kevin
0

Apenas para ser completo, C ++

#include <iostream>
#include <algorithm>
#include <string>

std::string theSeq = "abc";
do
{
  std::cout << theSeq << endl;
} 
while (std::next_permutation(theSeq.begin(), theSeq.end()));

...

abc
acb
bac
bca
cab
cba
AndersK
fonte
0

Aqui está uma solução não recursiva em C ++ que fornece a próxima permutação em ordem crescente, semelhante à funcionalidade fornecida por std :: next_permutation:

void permute_next(vector<int>& v)
{
  if (v.size() < 2)
    return;

  if (v.size() == 2)
  { 
    int tmp = v[0];
    v[0] = v[1];
    v[1] = tmp;
    return;
  }

  // Step 1: find first ascending-ordered pair from right to left
  int i = v.size()-2;
  while(i>=0)
  { 
    if (v[i] < v[i+1])
      break;
    i--;
  }
  if (i<0) // vector fully sorted in descending order (last permutation)
  {
    //resort in ascending order and return
    sort(v.begin(), v.end());
    return;
  }

  // Step 2: swap v[i] with next higher element of remaining elements
  int pos = i+1;
  int val = v[pos];
  for(int k=i+2; k<v.size(); k++)
    if(v[k] < val && v[k] > v[i])
    {
      pos = k;
      val = v[k];
    }
  v[pos] = v[i];
  v[i] = val;

  // Step 3: sort remaining elements from i+1 ... end
  sort(v.begin()+i+1, v.end());
}
Marios Choudary
fonte