Una tarea común en la programación de entrevistas (no desde mi experiencia con las entrevistas) es tomar una cadena o un número entero y enumerar todas las permutaciones posibles.
¿Hay un ejemplo de cómo se hace esto y la lógica detrás de resolver un problema así?
He visto algunos fragmentos de código, pero no fueron bien comentados / explicados y, por lo tanto, difíciles de seguir.
c#
algorithm
permutation
GurdeepS
fuente
fuente
Respuestas:
En primer lugar: ¡huele a recursión, por supuesto!
Como también querías conocer el principio, hice todo lo posible para explicarlo en lenguaje humano. Creo que la recursión es muy fácil la mayoría de las veces. Solo tienes que entender dos pasos:
En lenguaje humano :
Encontré el pseudocódigo en http://www.programmersheaven.com/mb/Algorithms/369713/369713/permutation-algorithm-help/ :
C#
OK, y algo más elaborado (y dado que está etiquetado como C #), de http://radio.weblogs.com/0111551/stories/2002/10/14/permutations.html : bastante largo, pero decidí copiarlo de todos modos, por lo que la publicación no depende del original.
ABC, ACB, BAC, BCA, CAB, CBA.
Código:
fuente
Swap(ref list[k], ref list[i]);
) no es necesario.(a[x], a[y]) = (a[y], a[x]);
Son solo dos líneas de código si se permite usar LINQ. Por favor vea mi respuesta aquí .
EDITAR
Aquí está mi función genérica que puede devolver todas las permutaciones (no combinaciones) de una lista de T:
Ejemplo:
Salida: una lista de listas enteras:
Como esta función usa LINQ, requiere .net 3.5 o superior.
fuente
const string s = "HALLOWEEN";
var result = GetPermutations(Enumerable.Range(0, s.Length), s.Length).Select(t => t.Select(i => s[i]));
Aquí he encontrado la solución. Fue escrito en Java, pero lo he convertido a C #. Espero que te ayude.
Aquí está el código en C #:
fuente
La recursión no es necesaria, aquí hay buena información sobre esta solución.
He usado este algoritmo durante años, tiene O (N) complejidad de tiempo y espacio para calcular cada permutación .
fuente
O(N-1)
para la secuencia yO(N)
para los intercambios, que esO(N)
. Y todavía estoy usando esto en producción pero con un refactor para generar solo una permutación como:GetPermutation(i)
where0 <= i <= N!-1
. Estaré encantado de usar algo con un mejor rendimiento que este, así que tenga la libertad de llamar a una referencia para algo mejor, la mayoría de las alternativas que utilizaO(N!)
en la memoria, por lo que también puede verificar eso.Puede escribir su función de intercambio para intercambiar caracteres.
Esto se llamará como permute (cadena, 0);
fuente
En primer lugar, los conjuntos tienen permutaciones, no cadenas o enteros, por lo que supongo que te refieres a "el conjunto de caracteres en una cadena".
Tenga en cuenta que un conjunto de tamaño n tiene n! n-permutaciones.
El siguiente pseudocódigo (de Wikipedia), llamado con k = 1 ... n! dará todas las permutaciones:
Aquí está el código Python equivalente (para índices de matriz basados en 0):
fuente
k := k / j;
hace.Versión ligeramente modificada en C # que produce permutaciones necesarias en una matriz de CUALQUIER tipo.
fuente
Permutations(vals).ToArray()
, terminas con N referencias a la misma matriz. Si desea poder almacenar los resultados, debe crear manualmente una copia. Por ejemploPermutations(values).Select(v => (T[])v.Clone())
fuente
Me gustó el enfoque FBryant87 ya que es simple. Desafortunadamente, le gustan muchas otras "soluciones" que no ofrecen todas las permutaciones o, por ejemplo, un número entero si contiene el mismo dígito más de una vez. Tome 656123 como ejemplo. La línea:
Excepto usando hará que todos los casos para ser eliminado, es decir, cuando c = 6, dos dígitos se eliminan y se quedan con, por ejemplo, 5123. Puesto que ninguna de las soluciones He intentado resuelto este, decidí probar y resolver yo mismo por FBryant87 s' código como base. Esto es lo que se me ocurrió:
Simplemente elimino la primera aparición encontrada usando .Remove e .IndexOf. Parece funcionar al menos según lo previsto para mi uso. Estoy seguro de que podría hacerse más inteligente.
Una cosa a tener en cuenta: la lista resultante puede contener duplicados, así que asegúrese de hacer que el método devuelva, por ejemplo, un HashSet o elimine los duplicados después de la devolución utilizando cualquier método que desee.
fuente
Aquí hay un buen artículo que cubre tres algoritmos para encontrar todas las permutaciones, incluido uno para encontrar la próxima permutación.
http://www.cut-the-knot.org/do_you_know/AllPerm.shtml
C ++ y Python tienen funciones incorporadas next_permutation e itertools.permutations respectivamente.
fuente
Aquí hay una implementación de F # puramente funcional:
El rendimiento puede mejorarse enormemente cambiando el intercambio para aprovechar la naturaleza mutable de los arreglos CLR, pero esta implementación es segura para subprocesos con respecto al arreglo fuente y eso puede ser deseable en algunos contextos. Además, para las matrices con más de 16 elementos, int debe reemplazarse por tipos con mayor precisión / arbitraria, ya que el factor 17 produce un desbordamiento int32.
fuente
Aquí hay una solución simple en C # usando recursión,
fuente
Aquí hay una función de permutación fácil de entender tanto para la cadena como para el entero como entrada. Con esto , incluso puede establecer la longitud de salida (que en el caso normal es igual a la longitud de entrada)
Cuerda
y para Integer simplemente cambie el método de llamada y MakePermutations () permanece intacto:
ejemplo 1: GetAllPermutations ("abc", 3); "abc" "acb" "bac" "bca" "cabina" "cba"
ejemplo 2: GetAllPermutations ("abcd", 2); "ab" "ac" "ad" "ba" "bc" "bd" "ca" "cb" "cd" "da" "db" "dc"
ejemplo 3: GetAllPermutations (486,2); 48 46 84 86 64 68
fuente
Aquí está la función que imprimirá todas las permutaciones. Esta función implementa la lógica explicada por Peter.
fuente
Lo siguiente es mi implementación de permutación. No importa los nombres de las variables, ya que lo estaba haciendo por diversión :)
fuente
Aquí hay un ejemplo de alto nivel que escribí que ilustra la explicación del lenguaje humano que Peter dio:
fuente
Si el rendimiento y la memoria son un problema, sugiero esta implementación muy eficiente. Según el algoritmo de Heap en Wikipedia , debería ser el más rápido. Espero que se ajuste a tu necesidad :-)!
¡Solo como comparación de esto con una implementación de Linq para 10! (código incluido):
Linq: 36288000 artículos en 50051 milisegundos
fuente
Aquí está mi solución en JavaScript (NodeJS). La idea principal es que tomamos un elemento a la vez, "lo eliminamos" de la cadena, variamos el resto de los caracteres e insertamos el elemento en la parte delantera.
Y aquí están las pruebas:
fuente
Aquí está la solución más simple que se me ocurre:
La
distribute
función toma un nuevo elementoe
y unan
lista de elementos y devuelve una lista den+1
listas cada una de las cuales se hae
insertado en un lugar diferente. Por ejemplo, insertando10
en cada uno de los cuatro lugares posibles en la lista[1;2;3]
:La
permute
función se pliega sobre cada elemento a su vez distribuyendo sobre las permutaciones acumuladas hasta el momento, culminando en todas las permutaciones. Por ejemplo, las 6 permutaciones de la lista[1;2;3]
:Cambiar el
fold
a ascan
para mantener los acumuladores intermedios arroja algo de luz sobre cómo las permutaciones se generan un elemento a la vez:fuente
Enumera las permutaciones de una cadena. Evita la duplicación cuando los caracteres se repiten:
fuente
Basándose en la solución de @ Peter, aquí hay una versión que declara un
Permutations()
método simple de extensión de estilo LINQ que funciona en cualquieraIEnumerable<T>
.Uso (en caracteres de cadena ejemplo):
Salidas:
O en cualquier otro tipo de colección:
Salidas:
fuente
Aquí está la función que imprimirá todas las permutaciones de forma recursiva.
fuente
fuente
Aquí hay una respuesta de C # que está un poco simplificada.
Salida:
fuente
Esta es mi solución que me es fácil de entender.
fuente
Aquí hay una implementación más del algo mencionado.
fuente
new Permutation().GenerateFor("aba")
salidasstring[4] { "ab", "baa", "baa", "ab" }
fuente
fuente