Quiero escribir una función que tome una matriz de letras como argumento y varias de esas letras para seleccionar.
Supongamos que proporciona una matriz de 8 letras y desea seleccionar 3 letras de eso. Entonces deberías obtener:
8! / ((8 - 3)! * 3!) = 56
Matrices (o palabras) a cambio que consisten en 3 letras cada una.
algorithm
combinations
ique
fuente
fuente
Respuestas:
Arte de la programación de computadoras Volumen 4: el Fascículo 3 tiene un montón de estos que podrían adaptarse mejor a su situación particular de lo que describo.
Códigos grises
Un problema que encontrará es, por supuesto, la memoria y bastante rápido, tendrá problemas con 20 elementos en su conjunto: 20 C 3 = 1140. Y si desea iterar sobre el conjunto, es mejor usar un gris modificado algoritmo de código para que no los tenga todos en la memoria. Estos generan la siguiente combinación de la anterior y evitan repeticiones. Hay muchos de estos para diferentes usos. ¿Queremos maximizar las diferencias entre combinaciones sucesivas? ¿minimizar? etcétera.
Algunos de los documentos originales que describen códigos grises:
Aquí hay algunos otros documentos que cubren el tema:
Chase's Twiddle (algoritmo)
Phillip J Chase, ` Algoritmo 382: Combinaciones de M de N objetos '(1970)
El algoritmo en C ...
Índice de combinaciones en orden lexicográfico (algoritmo de hebillas 515)
También puede hacer referencia a una combinación por su índice (en orden lexicográfico). Al darnos cuenta de que el índice debería ser una cantidad de cambio de derecha a izquierda en función del índice, podemos construir algo que debería recuperar una combinación.
Entonces, tenemos un conjunto {1,2,3,4,5,6} ... y queremos tres elementos. Digamos {1,2,3} podemos decir que la diferencia entre los elementos es uno y en orden y mínima. {1,2,4} tiene un cambio y es lexicográficamente el número 2. Por lo tanto, el número de 'cambios' en el último lugar representa un cambio en el orden lexicográfico. El segundo lugar, con un cambio {1,3,4} tiene un cambio, pero representa más cambios ya que está en el segundo lugar (proporcional al número de elementos en el conjunto original).
El método que describí es una deconstrucción, como parece, desde el conjunto al índice, necesitamos hacer lo contrario, lo cual es mucho más complicado. Así es como Buckles resuelve el problema. Escribí algo de C para calcularlos , con cambios menores: utilicé el índice de los conjuntos en lugar de un rango de números para representar el conjunto, por lo que siempre estamos trabajando desde 0 ... n. Nota:
Índice de combinaciones en orden lexicográfico (McCaffrey)
Hay otra forma : su concepto es más fácil de entender y programar, pero no tiene las optimizaciones de Buckles. Afortunadamente, tampoco produce combinaciones duplicadas:
El conjunto que maximiza , dónde .
Para un ejemplo:
27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Entonces, la 27ª combinación lexicográfica de cuatro cosas es: {1,2,5,6}, esos son los índices de cualquier conjunto que desee ver. Ejemplo a continuación (OCaml), requierechoose
función, se deja al lector:Un iterador de combinaciones pequeñas y simples
Los siguientes dos algoritmos se proporcionan con fines didácticos. Implementan un iterador y combinaciones generales de carpetas (más generales). Son lo más rápidos posible, tienen la complejidad O ( n C k ). El consumo de memoria está limitado por
k
.Comenzaremos con el iterador, que llamará a una función proporcionada por el usuario para cada combinación
Una versión más general llamará a la función proporcionada por el usuario junto con la variable de estado, comenzando desde el estado inicial. Como necesitamos pasar el estado entre diferentes estados, no usaremos el bucle for, sino que usaremos recursividad,
fuente
C ª#:
Uso:
Resultado:
fuente
var result = new[] { 1, 2, 3, 4, 5 }.Combinations(3);
Solución java corta:
El resultado será
fuente
¿Puedo presentar mi solución recursiva de Python a este problema?
Ejemplo de uso:
Me gusta por su simplicidad.
fuente
len(tuple(itertools.combinations('abcdefgh',3)))
logrará lo mismo en Python con menos código.for i in xrange(len(elements) - length + 1):
? No importa en Python, ya que salir del índice de corte se maneja con gracia, pero es el algoritmo correcto.Digamos que su conjunto de letras se ve así: "ABCDEFGH". Tiene tres índices (i, j, k) que indican qué letras va a utilizar para la palabra actual. Comienza con:
Primero varía k, por lo que el siguiente paso se ve así:
Si llegaste al final, continúas y varías j y luego k nuevamente.
Una vez que j llegó a G, comienza a variar también i.
Escrito en código esto se ve así
fuente
El siguiente algoritmo recursivo selecciona todas las combinaciones de elementos k de un conjunto ordenado:
i
de tu combinacióni
con cada una de las combinaciones dek-1
elementos elegidos recursivamente del conjunto de elementos mayores quei
.Iterar lo anterior para cada
i
en el conjunto.Es esencial que elija el resto de los elementos como más grandes
i
para evitar repeticiones. De esta forma, [3,5] se seleccionará solo una vez, ya que [3] se combinará con [5], en lugar de dos veces (la condición elimina [5] + [3]). Sin esta condición, obtienes variaciones en lugar de combinaciones.fuente
En C ++, la siguiente rutina producirá todas las combinaciones de distancia de longitud (primero, k) entre el rango [primero, último):
Se puede usar así:
Esto imprimirá lo siguiente:
fuente
being
ybegin
cons.begin()
yend
cons.end()
. El código sigue de cerca elnext_permutation
algoritmo de STL , descrito aquí con más detalles.Encontré este hilo útil y pensé que agregaría una solución de Javascript que puede introducir en Firebug. Dependiendo de su motor JS, podría llevar un poco de tiempo si la cadena de inicio es grande.
El resultado debe ser el siguiente:
fuente
fuente
Breve ejemplo en Python:
Para explicación, el método recursivo se describe con el siguiente ejemplo:
Ejemplo: ABCDE
Todas las combinaciones de 3 serían:
fuente
Algoritmo recursivo simple en Haskell
Primero definimos el caso especial, es decir, seleccionamos cero elementos. Produce un único resultado, que es una lista vacía (es decir, una lista que contiene una lista vacía).
Para n> 0,
x
recorre cada elemento de la lista yxs
es cada elemento posteriorx
.rest
seleccionan - 1
elementos delxs
uso de una llamada recursiva acombinations
. El resultado final de la función es una lista donde cada elemento esx : rest
( es decir, una lista que tienex
como cabeza yrest
como cola) para cada valor diferente dex
yrest
.Y, por supuesto, dado que Haskell es vago, la lista se genera gradualmente según sea necesario, por lo que puede evaluar parcialmente combinaciones exponencialmente grandes.
fuente
Y aquí viene el abuelo COBOL, el lenguaje muy difamado.
Supongamos una matriz de 34 elementos de 8 bytes cada uno (selección puramente arbitraria). La idea es enumerar todas las combinaciones posibles de 4 elementos y cargarlas en una matriz.
Utilizamos 4 índices, uno para cada posición en el grupo de 4
La matriz se procesa así:
Variamos idx4 desde 4 hasta el final. Para cada idx4 obtenemos una combinación única de grupos de cuatro. Cuando idx4 llega al final de la matriz, incrementamos idx3 en 1 y establecemos idx4 en idx3 + 1. Luego ejecutamos idx4 hasta el final nuevamente. Procedemos de esta manera, aumentando idx3, idx2 e idx1 respectivamente hasta que la posición de idx1 sea inferior a 4 desde el final de la matriz. Eso termina el algoritmo.
Primeras iteraciones:
Un ejemplo de COBOL:
fuente
Aquí hay una implementación elegante y genérica en Scala, como se describe en 99 Problemas de Scala .
fuente
Si puede usar la sintaxis SQL, por ejemplo, si está usando LINQ para acceder a los campos de una estructura o matriz, o está accediendo directamente a una base de datos que tiene una tabla llamada "Alfabeto" con un solo campo de caracteres "Letra", puede adaptar lo siguiente código:
Esto devolverá todas las combinaciones de 3 letras, independientemente de cuántas letras tenga en la tabla "Alfabeto" (puede ser 3, 8, 10, 27, etc.).
Si lo que desea son todas las permutaciones, en lugar de combinaciones (es decir, desea que "ACB" y "ABC" cuenten como diferentes, en lugar de aparecer solo una vez), simplemente elimine la última línea (la Y) y listo.
Post-Edición: después de volver a leer la pregunta, me doy cuenta de que lo que se necesita es el algoritmo general , no solo uno específico para el caso de seleccionar 3 elementos. La respuesta de Adam Hughes es completa, desafortunadamente no puedo votarla (todavía). Esta respuesta es simple pero solo funciona cuando quieres exactamente 3 elementos.
fuente
Otra versión de C # con generación perezosa de los índices de combinación. Esta versión mantiene una única matriz de índices para definir un mapeo entre la lista de todos los valores y los valores para la combinación actual, es decir, usa constantemente espacio adicional O (k) durante todo el tiempo de ejecución. El código genera combinaciones individuales, incluida la primera, en el tiempo O (k) .
Código de prueba:
Salida:
fuente
c b a
lo que no contiene .https://gist.github.com/3118596
Hay una implementación para JavaScript. Tiene funciones para obtener combinaciones k y todas las combinaciones de una matriz de cualquier objeto. Ejemplos:
fuente
Aquí tiene una versión perezosa evaluada de ese algoritmo codificada en C #:
Y parte de prueba:
Espero que esto te ayude!
fuente
Tenía un algoritmo de permutación que usé para el proyecto euler, en python:
Si
deberías tener toda la combinación que necesitas sin repetición, ¿la necesitas?
Es un generador, así que lo usa en algo como esto:
fuente
fuente
Versión Clojure:
fuente
Digamos que su conjunto de letras se ve así: "ABCDEFGH". Tiene tres índices (i, j, k) que indican qué letras va a utilizar para la palabra actual. Comienza con:
Primero varía k, por lo que el siguiente paso se ve así:
Si llegaste al final, continúas y varías j y luego k nuevamente.
Una vez que j llegó a G, comienza a variar también i.
Basado en https://stackoverflow.com/a/127898/2628125 , pero más abstracto, para cualquier tamaño de punteros.
fuente
Todo dicho y hecho aquí viene el código O'caml para eso. Algoritmo es evidente por el código.
fuente
Aquí hay un método que le brinda todas las combinaciones de tamaño especificado de una cadena de longitud aleatoria. Similar a la solución de quinmars, pero funciona para entradas variadas y k.
El código se puede cambiar para envolver, es decir, 'dab' de la entrada 'abcd' wk = 3.
Salida para "abcde":
fuente
código corto de Python, produciendo posiciones de índice
fuente
Creé una solución en SQL Server 2005 para esto y la publiqué en mi sitio web: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql.htm
Aquí hay un ejemplo para mostrar el uso:
resultados:
fuente
Aquí está mi propuesta en C ++
Intenté imponer tan poca restricción en el tipo de iterador como pude, por lo que esta solución asume solo el iterador directo, y puede ser un const_iterator. Esto debería funcionar con cualquier contenedor estándar. En casos donde los argumentos no tienen sentido, arroja std :: invalid_argumnent
fuente
Aquí hay un código que escribí recientemente en Java, que calcula y devuelve toda la combinación de elementos "num" a partir de elementos "outOf".
fuente
Una solución concisa de Javascript:
fuente
Algoritmo:
C ª#:
Por que funciona
Hay una biyección entre los subconjuntos de un conjunto de elementos n y secuencias de n bits.
Eso significa que podemos calcular cuántos subconjuntos hay contando secuencias.
por ejemplo, el conjunto de cuatro elementos a continuación puede representarse mediante {0,1} X {0, 1} X {0, 1} X {0, 1} (o 2 ^ 4) secuencias diferentes.
Entonces, todo lo que tenemos que hacer es contar de 1 a 2 ^ n para encontrar todas las combinaciones.(Ignoramos el conjunto vacío). Luego, traduzca los dígitos a su representación binaria. Luego, sustituya los elementos de su conjunto por bits 'on'.
Si solo desea resultados de k elementos, imprima solo cuando k bits estén 'activados'.
(Si desea todos los subconjuntos en lugar de los subconjuntos de longitud k, elimine la parte cnt / kElement).
(Para ver una prueba, consulte el curso gratuito MIT Mathematics for Computer Science, Lehman et al, sección 11.2.2. Https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-042j-mathematics- para-informática-otoño-2010 / lecturas / )
fuente
He escrito una clase para manejar funciones comunes para trabajar con el coeficiente binomial, que es el tipo de problema en el que se encuentra su problema. Realiza las siguientes tareas:
Emite todos los índices K en un formato agradable para cualquier N, elija K en un archivo. Los índices K pueden sustituirse por cadenas o letras más descriptivas. Este método hace que resolver este tipo de problema sea bastante trivial.
Convierte los índices K en el índice adecuado de una entrada en la tabla de coeficientes binomiales ordenados. Esta técnica es mucho más rápida que las técnicas publicadas más antiguas que se basan en la iteración. Lo hace usando una propiedad matemática inherente al Triángulo de Pascal. Mi artículo habla de esto. Creo que soy el primero en descubrir y publicar esta técnica, pero podría estar equivocado.
Convierte el índice en una tabla ordenada de coeficientes binomiales a los índices K correspondientes.
Utiliza el método Mark Dominus para calcular el coeficiente binomial, que es mucho menos probable que se desborde y funciona con números más grandes.
La clase está escrita en .NET C # y proporciona una forma de administrar los objetos relacionados con el problema (si corresponde) mediante una lista genérica. El constructor de esta clase toma un valor bool llamado InitTable que, cuando sea verdadero, creará una lista genérica para contener los objetos a administrar. Si este valor es falso, no creará la tabla. No es necesario crear la tabla para realizar los 4 métodos anteriores. Se proporcionan métodos de acceso para acceder a la tabla.
Hay una clase de prueba asociada que muestra cómo usar la clase y sus métodos. Ha sido ampliamente probado con 2 casos y no hay errores conocidos.
Para leer sobre esta clase y descargar el código, vea Tablizing The Binomial Coeffieicent .
No debería ser difícil convertir esta clase a C ++.
fuente