Cómo resolver el problema ‘Eliminar la cadena’ (PSTRING) en SPOJ

Después de buscar en Internet y discutir este problema con algunos de mis amigos, he solucionado este problema. Este problema es una combinación de algoritmo KMP y DP.
Deje que x [] e y [] tengan su significado habitual de la pregunta, MAXY y MAXX sean la longitud máxima de las cadenas correspondientes. Ahora cree una coincidencia de matriz [MAXY] [26]. La explicación en la siguiente sección nos ayudará a entender por qué esta matriz es útil.

match [i] [j] almacenará la longitud máxima del sufijo de la cadena (que se construye tomando el primer carácter i de y [] y el último carácter es j), que también es un prefijo de y []
Por ejemplo, si y [] = “ababc”, haga coincidir [4] [a] = 3. Esto se debe a que si construimos una cadena a partir de los primeros 4 caracteres de y [] y agregamos “a” en el último, lo haremos obtener “ababa”. Y ahora el sufijo más largo de esta cadena que también es un prefijo de y [] es “aba”. Podemos construir esta coincidencia de matriz [MAXY] [26] llamando repetidamente computeFailureFunction (cadena S) con diferente S (= y [0..i-1] + j para diferentes i y j) cada vez. La complejidad temporal del relleno de la matriz de coincidencias es [matemática] \ matemática {O} (| Y | ^ 2) [/ matemática] .

Después de completar este paso, nuestra definición y formulación de dp se verá más o menos así.

dp [i] [j] almacenará la longitud máxima de la subsecuencia (no la subcadena, ya que es posible que tengamos que soltar algunos caracteres de x) de x [0..i] de modo que el sufijo más largo de esta cadena, que también es un prefijo de y [] es de longitud j.
Así que ahora hay dos posibilidades para cualquier carácter de x [], ya sea soltar x [i] o retenerlo.

  1. Si dejamos caer x [i] entonces dp [i] [j] = dp [i-1] [j]
  2. De lo contrario, conservamos x [i], entonces nuevamente hay dos posibilidades, ya sea el sufijo que coincide hasta ahora (sufijo de la cadena construida que también es un prefijo de y []) aumentará en 1 (x [i] == y [j]) o disminuirá (x [i]! = y [j])
    1. Si x [i] == y [j] y j! = Ylen-1, entonces dp [i] [j + 1] = dp [i-1] [j] + 1. Esto se debe a que x [i] coincide con y [j] para que la longitud del sufijo coincidente que también es un prefijo de y [] se incremente en 1, por lo que ahora rellenaremos dp [i] [j + 1]. Y a medida que conservamos x [i] nuestra respuesta debería aumentar en 1 que antes.
    2. Si x [i]! = Y [j] entonces dp [i] [coincidencia] = dp [i-1] [j] + 1. Aquí x [i] no coincide con y [j] por lo que hemos encontrado un nueva coincidencia (la coincidencia es el sufijo más largo de la cadena construida, que también es un prefijo de y []) de la cadena construida con y []. Como sabemos en el paso i-1, los caracteres j ya coinciden, es decir, y [0..j-1] == cadena incorporada [ij..i-1]. Ahora, para encontrar una nueva coincidencia más larga, tenemos que encontrar un sufijo de cadena y [0..j-1] + x [i] (= construir cadena [ij..i]) que también es un prefijo de cadena y [] , y eso es exactamente igual a coincidir [j] [x [i]] , que hemos calculado previamente.

El caso base será si x [0] == y [0] luego dp [0] [1] = 1 y dp [0] [0] = 1. Después de calcular la matriz dp, encuentre el valor máximo en la matriz dp [xlen -1]. Deje que el valor máximo sea max. Entonces nuestro ans será xlen-max . La complejidad temporal de este algoritmo es [matemática] \ matemática {O} (| X || Y | + | Y | ^ 2) [/ matemática].

No he resuelto personalmente este problema y no estoy seguro de si será aceptado en un servidor, pero aquí hay algunas ideas.

Suponga que tiene una función F (x1, y1) que indica cuántos símbolos se eliminaron de la subcadena [0, x1] de X (1) de modo que y1 es la longitud de la subcadena común del sufijo de (1) y el prefijo de Y.

Básicamente, x1 es el número de símbolos procesados ​​desde X, X [0, x1] es una cadena procesada.
y1 es la longitud de la subcadena común del prefijo Y y el sufijo de X [0, x1]

Ahora, digamos que procesamos los símbolos x1 de X. Cuando obtenemos el símbolo x1 + 1, hay dos opciones: omitir el símbolo (eliminarlo) o no omitirlo.
El símbolo de omisión conducirá a una eliminación adicional que debemos contar, no omitir provocará cambios en la cadena común.

F (x1 + 1, y1) = min (F (x1, y1) +1 / * simplemente elimine el símbolo en la posición x1 + 1, la parte común no se cambiará * /, F (x1, y2));

y2 es algo que necesitarías calcular. Sabes que solía ser una cadena común de longitud y1, ahora obtienes el carácter adicional X [x1 + 1]. Aquí puede usar una técnica similar a KMP con la función de prefijo precompilación para descubrir el nuevo valor de y2.

El resultado será min (foreach i de 0 a Y.length () – 1 F (X.length (), i)).
La cadena X está completamente procesada y la longitud de la parte común está entre 0 e Y.length () – 1.

Suponiendo que conoces el algoritmo KMP o Z

Cada vez que obtenga una combinación perfecta de Y en X, inserte este índice en una matriz. Luego usamos un enfoque codicioso. Recorre linealmente la matriz obtenida.

prev = 0;

Si obtienes un valor tal que

A [idx] -a [prev]> strlen (Y),

luego responda ++, prev = idx.

Al final, para evitar un error, marque y agregue 1 a la respuesta.

¿Por qué funciona codicioso ? Es porque no podemos dejar de cubrir ningún índice en la matriz obtenida. Para cubrir todos los valores en A, tenemos que agruparlos en conjuntos disjuntos donde cada conjunto tiene algunos índices consecutivos de A. A ya estaba ordenado cuando lo creamos (debido a la función transversal transversal de falla). En cada uno de estos conjuntos, el valor del extremo derecho-valor del extremo izquierdo debe ser menor o igual que strlen (Y) para garantizar la superposición entre todas las subcadenas correspondientes a estos valores (estos valores son puntos finales de la subcadena siempre que haya una coincidencia perfecta). Por lo tanto, eliminar solo 1 carácter de la región superpuesta cubrirá todo el conjunto.

Parece que otras respuestas usaron DP. Quizás codicioso fallará en algún caso de prueba después de todo. Avíseme si codicioso funciona o no, de cualquier manera. Es más fácil de implementar, así que espero que pase.

Este problema se puede resolver con un algoritmo de programación dinámico y utilizando la función de falla del algoritmo KMP.

A continuación se detalla un esquema aproximado.
1. Calcule la función de falla para Y.
2. A medida que escanea X de izquierda a derecha, mantiene el sufijo más grande (de X visto hasta ahora) que también es un prefijo de Y. A medida que elige agregar o ignorar el carácter X actual, este sufijo más grande cambia. Debe hacer sus elecciones de tal manera que el sufijo más grande nunca esté lleno.

Esto nos da un tiempo de ejecución de O (| X | * | Y |), con un requisito de memoria de O (| Y |). No sé si hay un mejor algoritmo.

More Interesting

¿Qué curso de Udemy es mejor para aprender estructuras de datos si ya he aprendido los conceptos básicos (matrices, estructuras, punteros, listas enlazadas)?

¿Por qué alguien usa el hashing cuando el peor tiempo de búsqueda del hashing es O (n) y eso para bbst es logn?

Cómo detener un algoritmo que alguien más que yo ha establecido en WhatsApp

¿Qué es NP-hard y NP-complete?

¿Cuál es mi concepto erróneo con respecto al algoritmo de clasificación de fusión aquí?

Cómo aprender estructuras de datos y algoritmos lo suficientemente buenos como para conseguir un trabajo en 10 meses

Cómo ejecutar [(A * B) mod C] sin desbordamiento, si A y B son menores que C

¿Por qué no hay implementación de montón de Fibonacci en la API Java estándar?

¿Cuál es el algoritmo detrás de la agregación de noticias de Facebook News alrededor de una palabra clave en particular?

Cómo resolver ADAGAME en SPOJ

¿Es un árbol binario perfecto también un árbol binario completo?

¿Por qué usar un diagrama de flujo es una mala práctica en la programación?

En los lenguajes de programación donde una matriz crece dinámicamente en tamaño, ¿no es una preocupación porque es O (n) complejidad de tiempo?

¿Es correcto mi nuevo estado de ánimo? Ingresé a la programación desde un punto de vista de programación algorítmica y, como tal, tengo una inclinación a querer saber cómo funcionan las cosas debajo. Pero ahora, después de un tiempo en el mundo de los desarrolladores, finalmente tengo que darme cuenta de que se trata menos de eso. ¿Lo que usted dice?

¿Cuál es un ejemplo de un problema causado por la escritura dinámica en la programación?