Algoritmo de Manacher algoritmo de carro tirado por caballos (implementación de python)

Impresión a mano + dibujo, sin reimpresión

El algoritmo de carro tirado por caballos El algoritmo de Manacher es un método lineal utilizado para encontrar la subcadena palíndromo más larga de una cuerda. La mayor contribución de este método es aumentar la complejidad del tiempo a O (n) lineal.

—El algoritmo del carro tirado por caballos utiliza las características del palíndromo para evitar cálculos repetidos -

Paso 1: Inserte un "#" entre cada carácter de la cadena de entrada, como: S = "abcbaade", después de insertar la cadena se convierte en S '= "# a # b # c # b # a # a # d # e # ". Es fácil saber que el número de "#" insertados y el número de caracteres de cadena son diferentes en paridad, por lo que la longitud de la cadena procesada se vuelve impar, lo que unifica la paridad de la cadena.

Paso 2: Cree una nueva matriz P []. La longitud de P [] es la misma que la longitud de la cadena S procesada. P [i] almacena el radio del palíndromo en S '[i], que significa S' [i ] La longitud del palíndromo más grande centrado en el centro. Por ejemplo, la subcadena del palíndromo más larga centrada en S '[i] es S' [i, r], luego P [i] = r-i + 1. De esta forma, finalmente atraviesa la matriz P [] y toma el valor máximo. Si P [i] = 1, significa que el palíndromo es el propio T [i].

! La naturaleza especial de la matriz P []: el valor de P [i] correspondiente a S '[i] menos 1 es la longitud del palíndromo más largo correspondiente al carácter de la cadena original S

Cómo encontrar la matriz P []

Calcule la matriz P [] de izquierda a derecha, M es la posición central del palíndromo más grande obtenido anteriormente, y R y L son los valores que el palíndromo puede alcanzar en el extremo derecho y en el extremo izquierdo, respectivamente.

Caso 1: Cuando i <= R, use las características del palíndromo para encontrar el punto simétrico j del punto i con respecto a M, y su valor es j = M * 2-i, porque los puntos j e i son los más grandes centrados en M Dentro del rango del palíndromo [L, R]

Si P [j] <R-i (es decir, la distancia entre j y L), significa que el palíndromo centrado en el punto j no excede el rango [L, R]. P [j] puede verse en las características del palíndromo = P [i].

Si P [j]> = Ri (es decir, el extremo izquierdo del palíndromo más grande con j cuando el centro excede L), entonces los caracteres entre las características del palíndromo [L, j] no necesitan ser verificados y necesitan ser Verificado Es la parte sobrante> si hay un carácter simétrico sobre i en la parte R, continúe haciendo coincidir uno por uno desde R + 1 hasta que no pueda coincidir.

Caso 2: Cuando i> R, las características del palíndromo no se pueden usar, comenzando desde i + 1 para coincidir una por una

Ejemplo: subcadena de palíndromo máximo de LeetCode

  1. Subcadena palindrómica más larga - botón de permanencia (LeetCode) LeetCode palindrómica subcadena más larga Dada una cadena s, s para encontrar la subcadena palindrómica más larga. Puede asumir que la longitud máxima de s es 1000.


Ejemplo 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

Ejemplo 2:

输入: "cbbd"
输出: "bb"

Código de muestra de Python3:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        '''最长公共子串(动态规划) --- 超时'''
        # if len(s) == 1:
        #     return s
        # if len(s) == 0:
        #     return ""
        # l = len(s)
        # maxLength = 0
        # left = 0
        # right = 0
        # array = [[0 for i in range(0,l + 2)] for j in range(0,l + 2)]
        # for i in range(0,l):
        #     for j in range(0,l):
        #         if s[i] == s[j]:
        #             now = array[i][j+1] + 1
        #             array[i+1][j] = now
        #             if now > maxLength:
        #                 status = 0
        #                 for t in range(0,int(now/2) + 1):
        #                     if s[j + t] != s[j + now - t - 1]:
        #                         status = 1
        #                 if status == 0:
        #                     maxLength = now
        #                     left = j
        #                     right = j + maxLength 
        # return s[left:right]
        
        '''马拉车算法 --- 时间复杂度降低到线性'''
        S = "^#"
        for i in range(0,len(s)):
            S = S + s[i] + "#"
        S = S + "$"
        #print(S)
        P = [0 for i in range(0,len(S))]
        M = 0
        R = 0
        for i in range(1,len(S) - 1):
            j = M * 2 - i
            if R > i:
                if R - i > P[j]:
                    P[i] = P[j]
                else:
                    P[i] = R - i
            else:
                P[i] = 0
            # print("P[i]:" + str(P[i]))
            # print("i:" + str(i))
            # print("S[i]" + str(S[i]))
            while S[i + P[i] + 1] == S[i - P[i] - 1]:
                P[i] = P[i] + 1
                # print(P[i])
            
            if i + P[i] > R:
                R = i + P[i]
                M = i
        #print(P)
        Center = 0
        maxl = 0
        for i in range(1,len(S) - 1):
            if P[i] >= maxl:
                maxl = P[i]
                Center = i
        
        start = int((Center - maxl)/ 2)
        end = start + maxl
        # print(start)
        # print(end)
        return s[start:end]

Supongo que te gusta

Origin blog.csdn.net/weixin_42363722/article/details/110871649
Recomendado
Clasificación