📜  最短回文子串(1)

📅  最后修改于: 2023-12-03 14:55:22.740000             🧑  作者: Mango

最短回文子串

回文是指正序和逆序都一样的字符串。在字符串中查找最短回文子串是一个常见的问题,尤其在字符串处理和算法领域广泛应用。

本文将介绍最短回文子串问题的定义、解决方法和相关的代码实现,并提供了一些常见的算法技巧和优化方法。

问题定义

给定一个字符串,找到其中的最短回文子串。例如,在字符串 "abac" 中,最短回文子串为 "aba"。

解决方法

下面介绍两种常见的解决最短回文子串问题的方法:中心扩展法和动态规划。

中心扩展法

中心扩展法是最简单直观的解决方法之一。对于每个字符和每个字符间的空隙,以它们为中心向两边扩展,判断是否为回文子串,并记录最短长度。

  1. 遍历字符串中的每个字符。
  2. 分别以当前字符和相邻字符为中心,向两边扩展,判断是否为回文子串。
  3. 记录最短回文子串的起始和终止位置,以及长度。
  4. 返回最短回文子串。

中心扩展法的时间复杂度为 O(n^2),其中 n 是字符串的长度。

以下是使用 Python 实现中心扩展法的代码片段:

def expand_from_center(s, left, right):
    # 以 left 和 right 为中心向两边扩展,寻找回文子串
    while left >= 0 and right < len(s) and s[left] == s[right]:
        left -= 1
        right += 1
    return right - left - 1

def shortest_palindrome(s):
    # 特殊情况处理
    if len(s) <= 1:
        return s
    
    start, end = 0, 0
    for i in range(len(s)):
        # 以 s[i] 为中心的回文子串
        len1 = expand_from_center(s, i, i)
        # 以 s[i] 和 s[i+1] 为中心的回文子串
        len2 = expand_from_center(s, i, i + 1)
        # 记录最短回文子串的起始和终止位置
        length = min(len1, len2)
        if length > end - start:
            start = i - (length - 1) // 2
            end = i + length // 2
    
    return s[start:end+1]
动态规划

动态规划是解决最短回文子串问题的另一种常见方法。它基于以下观察:一个回文子串去除首尾字符后仍然是回文子串。

  1. 创建一个布尔矩阵 dp,其中 dp[i][j] 表示字符串的子串 s[i:j+1] 是否为回文串。
  2. 初始化 dp 为 False,除了矩阵的对角线 dp[i][i] 为 True,表示单个字符一定是回文串。
  3. 根据回文定义,如果 s[i] 等于 s[j] 且 s[i+1:j] 是回文串,则 s[i:j+1] 也是回文串。
  4. 根据动态规划状态转移方程计算 dp 数组。
  5. 遍历 dp 数组找到最短回文子串的长度和起始位置。
  6. 返回最短回文子串。

动态规划方法的时间复杂度为 O(n^2),其中 n 是字符串的长度。

以下是使用 Python 实现动态规划方法的代码片段:

def shortest_palindrome(s):
    # 特殊情况处理
    if len(s) <= 1:
        return s
    
    n = len(s)
    dp = [[False] * n for _ in range(n)]
    start, length = 0, 1
    
    for i in range(n):
        dp[i][i] = True
        
    for j in range(1, n):
        for i in range(j):
            # 如果当前字符相等,且去除首尾字符后是回文子串
            if s[i] == s[j] and (j - i <= 2 or dp[i+1][j-1]):
                dp[i][j] = True
                if j - i + 1 > length:
                    length = j - i + 1
                    start = i
    
    return s[start: start + length]
优化方法

在实际应用中,为了提高解决最短回文子串问题的效率,我们可以采用一些优化方法。

Manacher's 算法

Manacher's 算法是一种经典的解决最短回文子串问题的算法。它通过预处理字符串,将原始字符串扩展为长度为奇数的新字符串,在遍历新字符串时可以大大减少重复计算。

Manacher's 算法的时间复杂度为 O(n),其中 n 是字符串的长度。

这里提供了 Manacher's 算法的实现代码片段:

def pre_process(s):
    # 预处理字符串,插入特殊字符 #,将字符串长度转换为奇数
    n = len(s)
    if n == 0:
        return "^$"
    result = "^"
    for i in range(n):
        result += "#" + s[i]
    result += "#$"
    return result

def shortest_palindrome(s):
    # 特殊情况处理
    if len(s) <= 1:
        return s
    
    t = pre_process(s)
    n = len(t)
    p = [0] * n
    center, right = 0, 0
    
    for i in range(1, n - 1):
        mirror = 2 * center - i
        if right > i:
            p[i] = min(right - i, p[mirror])
        
        while t[i + 1 + p[i]] == t[i - 1 - p[i]]:
            p[i] += 1

        if i + p[i] > right:
            center = i
            right = i + p[i]
    
    max_len = max(p)
    center_index = p.index(max_len)
    start = (center_index - max_len) // 2
    
    return s[start: start + max_len]
总结

最短回文子串是一个常见的字符串处理问题,可以使用多种方法解决。中心扩展法和动态规划是两种常见的解决方法,其时间复杂度为 O(n^2)。为了进一步提高效率,我们还介绍了 Manacher's 算法,其时间复杂度为 O(n)。

通过理解和掌握这些解决方法,并结合实际应用中的优化技巧,可以更高效地解决最短回文子串问题。