Tienes dos problemas aquí. El primero es encontrar una permutación que maximice el número de coincidencias. Esto se puede lograr en tiempo lineal O (n). Comenzaría clasificando ambas cadenas usando un orden de conteo, que tiene una complejidad temporal de N. Luego invertiría las dos permutaciones, que también se pueden lograr en O (N). Entonces aquí puede ejecutar un algoritmo de “coincidencia” en tiempo lineal en la segunda cadena. Empieza asignando todas las A, luego las B y luego las C restando básicamente los recuentos del paso anterior. Luego haces otra carrera para (aleatoriamente o en orden) asignar los caracteres no utilizados. Una vez que haya hecho la coincidencia en la versión ordenada, puede aplicar el inverso de la primera cadena y obtendrá una permutación de la segunda cadena que coincida al máximo con la primera.
Aquí la clave es que esta operación preservará el número de coincidencias, ya que los caracteres que coinciden entre las cadenas ordenadas también coincidirán entre los “No clasificados”. Sin embargo, la única propiedad de las permutaciones que se ha utilizado es el hecho de que las permutaciones tienen inversa, que es una propiedad general de ser un grupo.
Esto es asintóticamente óptimo, ya que para calcular la mejor permutación necesita leer todos los caracteres al menos una vez.
- ¿Qué se usó antes de LaTeX para escribir documentos matemáticos? ¿Cómo se dibujaron las figuras? ¿Cómo se generaron y posicionaron las ecuaciones matemáticas con notación complicada en el documento? ¿Quién hizo la composición en su forma final para imprimir después de que fue aceptada?
- ¿La comunidad académica evita los intentos de resolver un problema NP-difícil en tiempo polinómico?
- Trabajo como desarrollador de software para una startup. Si sé que nuestro producto es falso, ¿debería cambiarme a otro trabajo?
- ¿Cómo resolvemos el siguiente problema en SPOJ utilizando aritmética modular inversa: SPOJ.com - Problema UCV2013A?
- ¿Cuál es el algoritmo para encontrar todas las soluciones de hacer 100 de 1-2-3-4-5-6-7-8-9 en orden?
Luego está el problema de encontrar todas (o muchas) de las permutaciones que son igualmente buenas. Aquí no tenemos las propiedades de grupo agradables porque la composición de dos permutaciones que dejan invariante el número de coincidencias puede no dejar invariable el número de coincidencias.
Si uno de los caracteres en la segunda cadena aparece menos que en la primera cadena, esto dejará un “espacio”, un carácter que no puede coincidir. Por ejemplo, si tienes:
ABABAC
FAACXR
Podrás unir las A como:
ABABAC
A -A – x –
ABABAC
A -x – A –
ABABAC
x – A – A –
Tenga en cuenta que puede identificar el número de espacios para cada letra comparando los recuentos después del orden de conteo. Aquí puede calcular fácilmente la cantidad de resultados que obtendrá. Este será el producto de todas las distribuciones posibles de huecos para cada personaje (la combinación del número de lugares en el número de huecos), estos son únicos, y luego todas las combinaciones posibles para llenar esos huecos. Luego, tendrás que multiplicar por la cantidad de formas de distribuir los caracteres restantes. Este será el factorial del número total de caracteres no coincidentes dividido por el producto de los factores de las repeticiones de cada carácter no coincidente (es decir (A + B + C + D)! / A! B! C! D! Donde A, B, C y D son los caracteres de la cadena 2 que no pudo asignar a un carácter de la cadena 1.
En cuanto a imprimirlo, mi única idea es iterar a través de todas las permutaciones. Esto le dará una complejidad temporal de N, que es asintóticamente óptima si planea imprimir / almacenar la permutación completa, necesitará una operación para cada personaje.
Esto no usa demasiadas propiedades de permutaciones, pero dado que tiene una complejidad lineal de tiempo, sería realmente difícil mejorarlo.
EDITAR: ejemplo de código agregado para el problema 1, ya que la explicación puede ser difícil de seguir.
#include
// Proporciona una permutación de originalString que está más cerca de targetString en O (n)
unsigned char *
findPermutation (const unsigned char * targetString, const unsigned char * originalString) {
unsigned int length = strlen ((const char *) originalString);
if (strlen ((const char *) targetString)! = length) devuelve NULL;
int countOriginal [256], scratchSpace [256];
int * countTarget = new int [257];
int * inversePermutation = new int [longitud];
unsigned char * opticalMatch = new unsigned char [longitud];
countTarget [0] = 0; countTarget–;
// Inicializar recuentos
para (int i = 0; i <256; i ++) {
countOriginal [i] = 0;
countTarget [i] = 0;
scratchSpace [i] = 0;
}
// Ordenar contando
for (unsigned int i = 0; i <length; i ++) {
countOriginal [originalString [i]] ++;
countTarget [targetString [i]] ++;
}
// Acumulación de recuento
para (int i = 1; i <256; i ++) countTarget [i] + = countTarget [i-1];
// Invertir permutación
for (unsigned int i = 0; i <length; i ++) {
inversePermutation [countTarget [targetString [i] -1] + scratchSpace [targetString [i]]] = i;
scratchSpace [targetString [i]] ++;
}
para (int i = 0; i <256; i ++) scratchSpace [i] = 0;
// Partido
para (int i = 0; i <256; i ++) {
para (int j = 0; ((j <countOriginal [i]) && (j <(countTarget [i] -countTarget [i-1]))); j ++) {
óptimaMatch [inversePermutation [(scratchSpace [i] ++) + countTarget [i-1]]] = i;
}
}
// Asigna caracteres no coincidentes
int targetChar = 0;
para (int i = 0; i <256; i ++) countOriginal [i] – = scratchSpace [i];
para (int i = 0; i <256; i ++) {
for (int j = 0; j <countOriginal [i]; j ++) {
while ((countTarget [targetChar] -countTarget [targetChar-1] -scratchSpace [targetChar]) == 0) targetChar ++;
óptimaMatch [inversePermutation [countTarget [targetChar-1] + scratchSpace [targetChar] ++]] = i;
}
}
// Limpiar
countTarget ++;
eliminar [] inversePermutation;
eliminar [] countTarget;
volver óptimoMatch;
}
En t
main (int argc, char * argv []) {
if (argc! = 3) {
std :: cout << "Debe usar dos cadenas como parámetros. \ n";
salida (1);
}
unsigned char * resultString = findPermutation ((const unsigned char *) argv [1], (const unsigned char *) argv [2]);
if (resultString == NULL) {
std :: cout << "Las dos cadenas deben ser de igual longitud \ n";
salida (1);
}
std :: cout << ((char *) resultString) << '\ n';
eliminar [] resultanteString;
}
Marcs-MacBook-Pro: ~ marc $ ./a.out alegres ratones
eosmus