Como se ha señalado, este problema es similar al problema de distancia de edición más comúnmente conocido (subyacente a la distancia de Levenshtein ). También tiene puntos en común con, por ejemplo, la distancia Dynamic Time Warping (la duplicación o "tartamudeo" en su último requisito).
Pasos hacia la programación dinámica.
x=x1…xny=y1…ymd(x,y)
min⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪d(x,y1…ym−1)+1d(x,y2…ym)+1d(x,y1…ym/2)+1d(x1…xn/2,y)+1d(x1…xn,y)+1d(x1…xn−1,y1…ym−1)if y=y1…ym/2y1…ym/2if x=x1…xn/2x1…xn/2if yn=ym▻ Add letter at end▻ Add letter at beginning▻ Doubling▻ Halving▻ Deletion▻ Ignoring last elt.
Aquí, la última opción básicamente dice que convertir FOOX a BARX es equivalente a convertir FOOX a BAR. Esto significa que puede usar la opción "agregar letra al final" para lograr el efecto de tartamudeo (duplicación) y la eliminación en un punto. El problema es que automáticamente le permite agregar un arbitraria de caracteres en el medio de la cadena , así , algo que probablemente no desea. (Este "ignorar los últimos elementos idénticos" es la forma estándar de lograr la eliminación y la tartamudez en posiciones arbitrarias. Sin embargo, prohibir las inserciones arbitrarias, al tiempo que permite adiciones en cualquier extremo, es un poco complicado ...)
He incluido este desglose a pesar de que no hace el trabajo por completo, en caso de que alguien más pueda "rescatarlo", de alguna manera, y porque lo uso en mi solución heurística, a continuación.
(Por supuesto, si pudiera obtener un desglose como este que realmente definiera su distancia, solo necesitaría agregar una memorización y tendría una solución. Sin embargo, debido a que no solo está trabajando con prefijos, no lo hago ' piense que podría usar solo índices para su memorización; es posible que tenga que almacenar las cadenas modificadas reales para cada llamada, lo que se volvería enorme si sus cadenas son de un tamaño considerable).
Pasos hacia una solución heurística
Otro enfoque, que podría ser más fácil de entender y que podría usar un poco menos de espacio, es buscar la "ruta de edición" más corta desde su primera cadena hasta la segunda, utilizando el algoritmo (básicamente, mejor- primero ramificado y atado). El espacio de búsqueda se definiría directamente por sus operaciones de edición. Ahora, para una cadena grande, que lo haríaA∗obtenga un vecindario grande, ya que podría eliminar cualquier carácter (dándole un vecino para cada eliminación potencial), o duplicar cualquier carácter (nuevamente, dándole un número lineal de vecinos), así como agregar cualquier carácter en cualquier extremo, lo que darle un número de vecinos igual al doble del tamaño del alfabeto. (Solo espero que no estés usando Unicode completo ;-) Con un fanout tan grande, podrías lograr una aceleración bastante sustancial usando un bidireccional , o algún parienteA∗ .
Para que funcione, necesitaría un límite inferior para la distancia restante a su objetivo. No estoy seguro de si hay una opción obvia aquí, pero lo que podría hacer es implementar una solución de programación dinámica basada en la descomposición recursiva que di anteriormente (nuevamente con posibles problemas de espacio si sus cadenas son muy largas). Mientras que la descomposición no calcula exactamente la distancia, que se garantiza que sea una cota inferior (porque es más permisiva), lo que significa que va a funcionar como una heurística en . (Lo apretado que será, no lo sé, pero sería correcto). Por supuesto, la memorización de su función enlazada podría compartirse en todos los cálculos del enlace durante suA∗A∗A∗correr. (Una compensación tiempo / espacio allí).
Entonces…
La eficiencia de mi solución propuesta parece depender bastante de (1) la longitud de sus cadenas y (2) el tamaño de su alfabeto. Si ninguno de los dos es enorme, podría funcionar. Es decir:
- Implemente el límite inferior a su distancia usando mi descomposición recursiva y programación dinámica (por ejemplo, usando una función recursiva y memorable).
- Implemente (o bidireccional ) con sus operaciones de edición como "movimientos" en el espacio de estado y el límite inferior basado en programación dinámica.A∗A∗
Realmente no puedo dar ninguna garantía de cuán eficiente sería, pero debería ser correcto, y probablemente sería mucho mejor que una solución de fuerza bruta.
Por lo menos, espero que esto te dé algunas ideas para futuras investigaciones.