Calcular la subcadena común más larga de dos cadenas utilizando matrices de sufijos

15

Después de aprender a construir una matriz de sufijos en complejidad O(N) , estoy interesado en descubrir las aplicaciones de las matrices de sufijos. Una de ellas es encontrar la subcadena común más larga entre dos cadenas, en el tiempo O(N) . Encontré en internet el siguiente algoritmo:

  1. fusionar las dos cadenas A y B en una cadena AB
  2. calcular la matriz de sufijos de AB
  3. calcular la matriz LCP (prefijo común más largo)
  4. la respuesta es el mayor valor LCP[i]

Traté de implementarlo, pero como no se dijeron muchos detalles de implementación (es decir, al concatenar las cadenas, ¿debería poner un carácter especial entre ellas ( )?), Mi código falló en muchos casos de prueba. ¿Alguien podría elaborar más sobre este algoritmo?AcB

Gracias por adelantado.

Nota: no garantizo la exactitud de este algoritmo; Lo encontré en un blog y no estoy seguro de que funcione. Si cree que es incorrecto, sugiera otro algoritmo.

Rontogiannis Aristofanis
fuente
3
Antes de implementar el algoritmo, intente entender por qué funciona. Eso podría ayudar a responder una pregunta como cómo concatenar dos cadenas.
Yuval Filmus
3
Dudo de la exactitud de este algoritmo. Tome y b c d , la forma en que lo leí devolverá a b c d , lo cual está mal. abcdabcdbcdabcd
Khaur

Respuestas:

20

Tu algoritmo es incorrecto . Supongo que sabe cómo calcular la matriz de sufijos y la matriz LCP de una cadena, es decir, su implementación eficiente. Como se ha señalado en los comentarios, debe intentar comprender qué es cada componente y por qué funciona.

En primer lugar, es la matriz de sufijos ( ) de una cadena. Una matriz de sufijos es básicamente todos los sufijos de la cadena S dispuestos en orden lexicográfico ascendente. Más específicamente, el valor S A [ i ] indica que el sufijo de S a partir de la posición S A [ i ] está clasificado como iSASSA[i]SSA[i]i en el orden lexicográfico de todos los sufijos de .S

Lo siguiente es la matriz L C P [ i ] indica la longitud del prefijo común más largo entre los sufijos que comienzan desde S A [ i - 1 ] y S A [ i ] . Es decir, realiza un seguimiento de la longitud del prefijo común más largo entre dos sufijos consecutivos de S cuando se disponen en orden lexicográfico.LCPLCP[i]SA[i1]SA[i]S

Como ejemplo, considere la cadena . Los sufijos en orden lexicográfico serían { a , a b b a b c a , a b c a , b a b c a , b b a b c a , b c a , c a } , entonces S A = [ 7 , 1S=abbabca{a,abbabca,abca,babca,bbabca,bca,ca} para una matriz indexada 1. Lamatriz L C P sería L C P = [ - , 1 , 2 , 0 , 1 , 1 , 0 ] .SA=[7,1,4,3,2,5,6]LCPLCP=[,1,2,0,1,1,0]

Ahora, dado dos cadenas y B , que les concatenar como S = A # B , donde # es un personaje no está presente tanto en A y B . La razón para elegir dicho carácter es para que al calcular el LCP de dos sufijos, diga a b # d a b d y a bABS=A#B#ABab#dabd , la comparación se interrumpa al final de la primera cadena (ya que solo ocurre una vez, dos sufijos diferentes nunca lo tendrán en la misma posición) y no se"desbordarán"en la otra cadena.abd

Ahora, se puede ver que debería poder ver por qué solo necesita ver valores consecutivos en la matriz (el argumento se basa en la contradicción y el hecho de que los sufijos en S A están en orden lexicográfico). Siga revisando la matriz L C P para ver el valor máximo de manera que los dos sufijos que se comparan no pertenezcan a la misma cadena original. Si no pertenecen a la misma cadena original (una comienza en A y la otra en B ), entonces el valor más grande es la longitud de la subcadena común más grande.LCPSALCPAB

Como ejemplo, considere y B = b c . Entonces, S = a b c a b c # b c . Los sufijos ordenados son { a b c # b c , a b c a b c # b c , b c , b c # b c , b c aA=abcabcB=bcS=abcabc#bc{abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}.
SA=[4,1,8,5,2,9,6,3,7]LCP=[,3,0,2,2,0,1,1,0]

LCP[2]=3SA[1]SA[2], both of which start in the string A. So, we ignore that. On the other hand, LCP[4]=2 is for SA[3] (corresponds to the suffix bc of B) and SA[4]bcabc#bcA2 LCPSA[3] or SA[4], which is bc.

Paresh
fuente
1
Excellent explanation but I think that the example is a bit wrong, the sorted suffixes are : {#bc,abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}, SA=[7,4,1,8,5,2,9,6,3] and LCP=[−,0,3,0,2,2,0,1,1]
Saúl Martínez Vidals
1

The algorithm you found online is not entirely correct. As mentioned by Paresh, it will fail in the example given by him.

However, if you ensure that while checking the LCP, you only check the LCP of substrings of different strings. For example, if you are finding the LCS of strings A and B, then you need to ensure that the adjacent entries of the Suffix Array while checking for LCP are both not from the same string.

More details here.

rohitjv
fuente
1
When you say "This answer", do you mean your own answer or some other answer? Please only use the answer box to answer the question, not to comment on other answers. When you've picked up enough reputation, you'll be able to leave comments on other answers.
David Richerby
0

I think something like the algorithm you cite should indeed work if a character that is not part of the character set is used as a separator, and the suffix/prefix arrays are built to exclude all strings that contain the separator, probably the intention of the designer. this is basically equivalent to building suffix/prefix arrays for the two separate strings.

it would be helpful for future ref if you posted a link to the algorithm. note that wikipedia has the algorithm for this in pseudocode & many other algorithms. and there are implementations in most standard languages available online.

vzn
fuente