Uma tarefa comum na programação de entrevistas (embora não da minha experiência em entrevistas) é pegar uma string ou um número inteiro e listar todas as permutações possíveis.
Existe um exemplo de como isso é feito e a lógica por trás da solução desse problema?
Eu vi alguns trechos de código, mas eles não foram bem comentados / explicados e, portanto, difíceis de seguir.
c#
algorithm
permutation
GurdeepS
fonte
fonte
Respostas:
Primeiro de tudo: cheira a recursão, é claro!
Como você também queria conhecer o princípio, fiz o possível para explicar a linguagem humana. Eu acho que a recursão é muito fácil na maioria das vezes. Você só precisa entender duas etapas:
Na linguagem humana :
Encontrei o pseudocódigo em http://www.programmersheaven.com/mb/Algorithms/369713/369713/permutation-algorithm-help/ :
C #
OK, e algo mais elaborado (e como está marcado c #), de http://radio.weblogs.com/0111551/stories/2002/10/14/permutations.html : Bastante demorado, mas decidi copiá-lo de qualquer maneira, a postagem não depende do original.
ABC, ACB, BAC, BCA, CAB, CBA.
Código:
fonte
Swap(ref list[k], ref list[i]);
) é desnecessária.(a[x], a[y]) = (a[y], a[x]);
São apenas duas linhas de código se o LINQ está autorizado a usar. Por favor, veja minha resposta aqui .
EDITAR
Aqui está minha função genérica que pode retornar todas as permutações (não combinações) de uma lista de T:
Exemplo:
Saída - uma lista de listas inteiras:
Como essa função usa o LINQ, requer .net 3.5 ou superior.
fonte
const string s = "HALLOWEEN";
var result = GetPermutations(Enumerable.Range(0, s.Length), s.Length).Select(t => t.Select(i => s[i]));
Aqui encontrei a solução. Foi escrito em Java, mas eu o converti para C #. Espero que ajude você.
Aqui está o código em C #:
fonte
A recursão não é necessária; aqui estão boas informações sobre esta solução.
Eu tenho usado esse algoritmo há anos, ele tem complexidade de tempo e espaço O (N) para calcular cada permutação .
fonte
O(N-1)
para a sequência eO(N)
para os swaps, o que éO(N)
. E ainda estou usando isso na produção, mas com um refator para gerar apenas uma permutação como:GetPermutation(i)
where0 <= i <= N!-1
. Ficarei feliz em usar algo com melhor desempenho do que isso; portanto, fique à vontade para chamar uma referência para algo melhor, a maioria das alternativas usaO(N!)
na memória para que você possa verificar isso também.Você pode escrever sua função de troca para trocar caracteres.
Isso deve ser chamado como permute (string, 0);
fonte
Antes de tudo, os conjuntos têm permutações, não seqüências de caracteres ou números inteiros; portanto, assumirei que você quer dizer "o conjunto de caracteres em uma sequência".
Observe que um conjunto de tamanho n tem n! n-permutações.
O seguinte pseudocódigo (da Wikipedia), chamado com k = 1 ... n! dará todas as permutações:
Aqui está o código Python equivalente (para índices de matriz baseados em 0):
fonte
k := k / j;
fazVersão ligeiramente modificada em C # que produz permutações necessárias em uma matriz de QUALQUER tipo.
fonte
Permutations(vals).ToArray()
, acabará com N referências à mesma matriz. Se você deseja armazenar os resultados, é necessário criar uma cópia manualmente. Por exemploPermutations(values).Select(v => (T[])v.Clone())
fonte
Eu gostei da abordagem FBryant87 , pois é simples. Infelizmente, muitas outras "soluções" não oferecem todas as permutações ou, por exemplo, um número inteiro se contiverem o mesmo dígito mais de uma vez. Tome 656123 como um exemplo. A linha:
usando Exceto fará com que todas as ocorrências de ser removidos, ou seja, quando c = 6, dois dígitos são removidos e ficamos com, por exemplo 5123. Desde nenhuma das soluções Tentei resolvido isso, eu decidi tentar e resolver isso sozinho por FBryant87 s' código como base. Isto é o que eu vim com:
Simplesmente remova a primeira ocorrência encontrada usando .Remove e .IndexOf. Parece funcionar como planejado para o meu uso, pelo menos. Tenho certeza de que poderia ser mais inteligente.
Porém, uma coisa a ser observada: A lista resultante pode conter duplicatas; portanto, faça com que o método retorne, por exemplo, um HashSet ou remova as duplicatas após o retorno usando o método que desejar.
fonte
Aqui está um bom artigo abordando três algoritmos para encontrar todas as permutações, incluindo um para encontrar a próxima permutação.
http://www.cut-the-knot.org/do_you_know/AllPerm.shtml
C ++ e Python têm funções internas next_permutation e itertools.permutations , respectivamente.
fonte
Aqui está uma implementação de F # puramente funcional:
O desempenho pode ser bastante aprimorado alterando a troca para tirar proveito da natureza mutável das matrizes CLR, mas essa implementação é segura para threads em relação à matriz de origem e pode ser desejável em alguns contextos. Além disso, para matrizes com mais de 16 elementos, int deve ser substituído por tipos com maior precisão / arbitrária, pois o fatorial 17 resulta em um estouro de int32.
fonte
Aqui está uma solução simples em c # usando recursão,
fonte
Aqui está uma função de permutação fácil de entender para string e número inteiro como entrada. Com isso, você pode até definir o tamanho da sua saída (que, no caso normal, é igual ao comprimento da entrada)
Corda
e para Integer, basta alterar o método de chamada e MakePermutations () permanece intocado:
exemplo 1: GetAllPermutations ("abc", 3); "abc" "acb" "bac" "bca" "cab" "cba"
exemplo 2: GetAllPermutations ("abcd", 2); "ab" "ac" "ad" "ba" "bc" "bd" "ca" "cb" "cd" "da" "db" "dc"
exemplo 3: GetAllPermutations (486,2); 48 46 84 86 64 68
fonte
Aqui está a função que imprimirá toda a permutação. Esta função implementa a lógica Explicada por Peter.
fonte
Abaixo está a minha implementação de permutação. Não se importe com os nomes das variáveis, pois eu estava fazendo isso por diversão :)
fonte
Aqui está um exemplo de alto nível que escrevi que ilustra a explicação da linguagem humana que Peter deu:
fonte
Se desempenho e memória são um problema, sugiro esta implementação muito eficiente. De acordo com o algoritmo de Heap na Wikipedia , deve ser o mais rápido. Espero que atenda às suas necessidades :-)!
Apenas como comparação com uma implementação do Linq para 10! (código incluído):
Linq: 36288000 itens em 50051 milissegundos
fonte
Aqui está minha solução em JavaScript (NodeJS). A idéia principal é pegar um elemento de cada vez, "removê-lo" da string, variar o restante dos caracteres e inserir o elemento na frente.
E aqui estão os testes:
fonte
Aqui está a solução mais simples que consigo pensar:
A
distribute
função pega um novo elementoe
e uman
lista de elementos e retorna uma lista den+1
listas que cada uma foie
inserida em um local diferente. Por exemplo, inserindo10
em cada um dos quatro locais possíveis na lista[1;2;3]
:A
permute
função se dobra sobre cada elemento, distribuindo as permutações acumuladas até o momento, culminando em todas as permutações. Por exemplo, as 6 permutações da lista[1;2;3]
:Mudar
fold
para para ascan
fim de manter os acumuladores intermediários lança alguma luz sobre como as permutações são geradas um elemento de cada vez:fonte
Lista permutações de uma sequência. Evita duplicação quando os caracteres são repetidos:
fonte
Com base na solução de @ Peter, aqui está uma versão que declara um
Permutations()
método simples de extensão no estilo LINQ que funciona em qualquerIEnumerable<T>
.Uso (no exemplo de caracteres de sequência):
Saídas:
Ou em qualquer outro tipo de coleção:
Saídas:
fonte
Aqui está a função que imprimirá todas as permutações recursivamente.
fonte
fonte
Aqui está uma resposta C # que é um pouco simplificada.
Resultado:
fonte
Esta é a minha solução que é fácil para mim entender
fonte
Aqui está mais uma implementação do algo mencionado.
fonte
new Permutation().GenerateFor("aba")
saídasstring[4] { "ab", "baa", "baa", "ab" }
fonte
fonte