返回

小兵出招,教你一行代码搞定最长回文子串!

前端

最长回文子串的定义

回文子串是指从左到右读和从右到左读都是一样的子串。例如,“abba”是一个回文子串,而“abc”不是。最长回文子串是指字符串中最长的回文子串。

Manacher算法

Manacher算法是一种解决最长回文子串问题的经典算法。该算法的基本思想是将每个字符作为一个回文子串的中心,然后向两边扩展,直到找到一个回文子串。

Manacher算法的步骤

  1. 在字符串的两端添加特殊字符“$”。
  2. 定义一个数组P,其中P[i]表示以第i个字符为中心的回文子串的长度。
  3. 初始化P[1]为1,P[2]为2。
  4. 从i = 3开始,依次计算P[i]。对于每个i,先找到最大的j,使得j < i且P[i - j - 1] <= j。然后,令P[i] = P[i - j - 1] + 2 * (i - j) + 1。
  5. 找到P[i]的最大值,并记录下对应的回文子串。

KMP算法

KMP算法是另一种解决最长回文子串问题的经典算法。该算法的基本思想是利用一个失败函数来快速跳过不匹配的字符。

KMP算法的步骤

  1. 预处理字符串,计算出失败函数。
  2. 从字符串的第一个字符开始,依次与失败函数中的值进行比较。
  3. 如果当前字符与失败函数中的值匹配,则向右移动一位。
  4. 如果当前字符与失败函数中的值不匹配,则根据失败函数的值跳过不匹配的字符。
  5. 重复步骤3和4,直到到达字符串的末尾。
  6. 记录下最长的匹配子串。

Manacher算法和KMP算法的比较

Manacher算法和KMP算法都是解决最长回文子串问题的经典算法。这两种算法都有各自的优缺点。Manacher算法的时间复杂度为O(n),空间复杂度为O(n),而KMP算法的时间复杂度为O(n^2),空间复杂度为O(n)。总体来说,Manacher算法在时间复杂度上更优,而KMP算法在空间复杂度上更优。

代码实现

def manacher(s):
    # 在字符串的两端添加特殊字符"
def manacher(s):
    # 在字符串的两端添加特殊字符"$"
    s = "$" + s + "$"
    # 定义数组P
    P = [0 for _ in range(len(s))]
    # 初始化P[1]和P[2]
    P[1] = 1
    P[2] = 2
    # 从i = 3开始,依次计算P[i]
    for i in range(3, len(s)):
        # 找到最大的j,使得j < i且P[i - j - 1] <= j
        j = 0
        while i - j - 1 >= 0 and i + j < len(s) and s[i - j - 1] == s[i + j]:
            j += 1
        # 令P[i] = P[i - j - 1] + 2 * (i - j) + 1
        P[i] = P[i - j - 1] + 2 * (i - j) + 1
    # 找到P[i]的最大值,并记录下对应的回文子串
    max_len = 0
    max_center = 0
    for i in range(len(s)):
        if P[i] > max_len:
            max_len = P[i]
            max_center = i
    # 去掉特殊字符"$"
    return s[max_center - max_len // 2:max_center + max_len // 2 + 1]


def kmp(s):
    # 预处理字符串,计算出失败函数
    n = len(s)
    fail = [0 for _ in range(n)]
    for i in range(1, n):
        j = fail[i - 1]
        while j > 0 and s[i] != s[j]:
            j = fail[j - 1]
        if s[i] == s[j]:
            j += 1
        fail[i] = j
    # 从字符串的第一个字符开始,依次与失败函数中的值进行比较
    max_len = 0
    max_start = 0
    for i in range(n):
        if fail[i] > max_len:
            max_len = fail[i]
            max_start = i - max_len + 1
    # 返回最长的匹配子串
    return s[max_start:max_start + max_len]


if __name__ == "__main__":
    s = "abba"
    print("最长回文子串:", manacher(s))
    print("最长回文子串:", kmp(s))
quot;
s = "
def manacher(s):
    # 在字符串的两端添加特殊字符"$"
    s = "$" + s + "$"
    # 定义数组P
    P = [0 for _ in range(len(s))]
    # 初始化P[1]和P[2]
    P[1] = 1
    P[2] = 2
    # 从i = 3开始,依次计算P[i]
    for i in range(3, len(s)):
        # 找到最大的j,使得j < i且P[i - j - 1] <= j
        j = 0
        while i - j - 1 >= 0 and i + j < len(s) and s[i - j - 1] == s[i + j]:
            j += 1
        # 令P[i] = P[i - j - 1] + 2 * (i - j) + 1
        P[i] = P[i - j - 1] + 2 * (i - j) + 1
    # 找到P[i]的最大值,并记录下对应的回文子串
    max_len = 0
    max_center = 0
    for i in range(len(s)):
        if P[i] > max_len:
            max_len = P[i]
            max_center = i
    # 去掉特殊字符"$"
    return s[max_center - max_len // 2:max_center + max_len // 2 + 1]


def kmp(s):
    # 预处理字符串,计算出失败函数
    n = len(s)
    fail = [0 for _ in range(n)]
    for i in range(1, n):
        j = fail[i - 1]
        while j > 0 and s[i] != s[j]:
            j = fail[j - 1]
        if s[i] == s[j]:
            j += 1
        fail[i] = j
    # 从字符串的第一个字符开始,依次与失败函数中的值进行比较
    max_len = 0
    max_start = 0
    for i in range(n):
        if fail[i] > max_len:
            max_len = fail[i]
            max_start = i - max_len + 1
    # 返回最长的匹配子串
    return s[max_start:max_start + max_len]


if __name__ == "__main__":
    s = "abba"
    print("最长回文子串:", manacher(s))
    print("最长回文子串:", kmp(s))
quot;
+ s + "
def manacher(s):
    # 在字符串的两端添加特殊字符"$"
    s = "$" + s + "$"
    # 定义数组P
    P = [0 for _ in range(len(s))]
    # 初始化P[1]和P[2]
    P[1] = 1
    P[2] = 2
    # 从i = 3开始,依次计算P[i]
    for i in range(3, len(s)):
        # 找到最大的j,使得j < i且P[i - j - 1] <= j
        j = 0
        while i - j - 1 >= 0 and i + j < len(s) and s[i - j - 1] == s[i + j]:
            j += 1
        # 令P[i] = P[i - j - 1] + 2 * (i - j) + 1
        P[i] = P[i - j - 1] + 2 * (i - j) + 1
    # 找到P[i]的最大值,并记录下对应的回文子串
    max_len = 0
    max_center = 0
    for i in range(len(s)):
        if P[i] > max_len:
            max_len = P[i]
            max_center = i
    # 去掉特殊字符"$"
    return s[max_center - max_len // 2:max_center + max_len // 2 + 1]


def kmp(s):
    # 预处理字符串,计算出失败函数
    n = len(s)
    fail = [0 for _ in range(n)]
    for i in range(1, n):
        j = fail[i - 1]
        while j > 0 and s[i] != s[j]:
            j = fail[j - 1]
        if s[i] == s[j]:
            j += 1
        fail[i] = j
    # 从字符串的第一个字符开始,依次与失败函数中的值进行比较
    max_len = 0
    max_start = 0
    for i in range(n):
        if fail[i] > max_len:
            max_len = fail[i]
            max_start = i - max_len + 1
    # 返回最长的匹配子串
    return s[max_start:max_start + max_len]


if __name__ == "__main__":
    s = "abba"
    print("最长回文子串:", manacher(s))
    print("最长回文子串:", kmp(s))
quot;
# 定义数组P P = [0 for _ in range(len(s))] # 初始化P[1]和P[2] P[1] = 1 P[2] = 2 # 从i = 3开始,依次计算P[i] for i in range(3, len(s)): # 找到最大的j,使得j < i且P[i - j - 1] <= j j = 0 while i - j - 1 >= 0 and i + j < len(s) and s[i - j - 1] == s[i + j]: j += 1 # 令P[i] = P[i - j - 1] + 2 * (i - j) + 1 P[i] = P[i - j - 1] + 2 * (i - j) + 1 # 找到P[i]的最大值,并记录下对应的回文子串 max_len = 0 max_center = 0 for i in range(len(s)): if P[i] > max_len: max_len = P[i] max_center = i # 去掉特殊字符"
def manacher(s):
    # 在字符串的两端添加特殊字符"$"
    s = "$" + s + "$"
    # 定义数组P
    P = [0 for _ in range(len(s))]
    # 初始化P[1]和P[2]
    P[1] = 1
    P[2] = 2
    # 从i = 3开始,依次计算P[i]
    for i in range(3, len(s)):
        # 找到最大的j,使得j < i且P[i - j - 1] <= j
        j = 0
        while i - j - 1 >= 0 and i + j < len(s) and s[i - j - 1] == s[i + j]:
            j += 1
        # 令P[i] = P[i - j - 1] + 2 * (i - j) + 1
        P[i] = P[i - j - 1] + 2 * (i - j) + 1
    # 找到P[i]的最大值,并记录下对应的回文子串
    max_len = 0
    max_center = 0
    for i in range(len(s)):
        if P[i] > max_len:
            max_len = P[i]
            max_center = i
    # 去掉特殊字符"$"
    return s[max_center - max_len // 2:max_center + max_len // 2 + 1]


def kmp(s):
    # 预处理字符串,计算出失败函数
    n = len(s)
    fail = [0 for _ in range(n)]
    for i in range(1, n):
        j = fail[i - 1]
        while j > 0 and s[i] != s[j]:
            j = fail[j - 1]
        if s[i] == s[j]:
            j += 1
        fail[i] = j
    # 从字符串的第一个字符开始,依次与失败函数中的值进行比较
    max_len = 0
    max_start = 0
    for i in range(n):
        if fail[i] > max_len:
            max_len = fail[i]
            max_start = i - max_len + 1
    # 返回最长的匹配子串
    return s[max_start:max_start + max_len]


if __name__ == "__main__":
    s = "abba"
    print("最长回文子串:", manacher(s))
    print("最长回文子串:", kmp(s))
quot;
return s[max_center - max_len // 2:max_center + max_len // 2 + 1] def kmp(s): # 预处理字符串,计算出失败函数 n = len(s) fail = [0 for _ in range(n)] for i in range(1, n): j = fail[i - 1] while j > 0 and s[i] != s[j]: j = fail[j - 1] if s[i] == s[j]: j += 1 fail[i] = j # 从字符串的第一个字符开始,依次与失败函数中的值进行比较 max_len = 0 max_start = 0 for i in range(n): if fail[i] > max_len: max_len = fail[i] max_start = i - max_len + 1 # 返回最长的匹配子串 return s[max_start:max_start + max_len] if __name__ == "__main__": s = "abba" print("最长回文子串:", manacher(s)) print("最长回文子串:", kmp(s))