📅  最后修改于: 2023-12-03 15:23:01.929000             🧑  作者: Mango
回文指的是正反顺序读起来都一样的字符串,例如“level”,“racecar”,“deed”等。
回文子串查询是指找出给定字符串中所有的回文子串。
最直观的想法是枚举所有子串,然后判断是否为回文。这种方法的时间复杂度为 $O(n^3)$,不适合处理较长的字符串。
代码片段:
def is_palindrome(s: str) -> bool:
return s == s[::-1]
def find_all_palindromes(s: str) -> List[str]:
n = len(s)
res = []
for i in range(n):
for j in range(i+1, n+1):
if is_palindrome(s[i:j]):
res.append(s[i:j])
return res
回文串是以中心对称的,因此可以枚举回文串的中心,然后向两边扩展。
注意,回文串的中心可能是一个字符,也可能是两个字符之间的空隙,因此中心的个数是 $2n-1$ 个。
代码片段:
def find_all_palindromes(s: str) -> List[str]:
n = len(s)
res = []
for i in range(2*n-1):
l, r = i//2, i//2+i%2
while l >= 0 and r < n and s[l] == s[r]:
res.append(s[l:r+1])
l -= 1
r += 1
return res
时间复杂度为 $O(n^2)$。
Manacher 算法是解决回文串问题的经典算法,时间复杂度为 $O(n)$。
Manacher 算法的核心思想是利用已经计算出来的回文信息,尽可能地减少重复计算。
具体来说,定义 $p_i$ 表示以位置 $i$ 为中心的最长回文半径,$mx$ 表示当前所有回文子串的右端点中最大者,$id$ 表示所有回文子串中右端点最大者的位置。
则有以下两种情况:
代码片段:
def find_all_palindromes(s: str) -> List[str]:
t = '^#' + '#'.join(s) + '#$'
n = len(t)
p = [0] * n
id, mx = 0, 0
for i in range(1, n-1):
if i < mx:
p[i] = min(p[2*id-i], mx-i)
while t[i+p[i]+1] == t[i-p[i]-1]:
p[i] += 1
if i + p[i] > mx:
mx = i + p[i]
id = i
res = []
for i in range(1, n-1):
l, r = (i-p[i])//2, (i+p[i])//2
res.append(s[l:r])
return res
回文子串查询是一个常见的字符串问题,有多种解法可供选择。暴力枚举的时间复杂度较高,不适合处理较长的字符串。中心扩展法的时间复杂度为 $O(n^2)$,相对来说比较高效。Manacher 算法的时间复杂度为 $O(n)$,是最优解法。
代码片段中的函数签名为示例,具体实现可以根据需要进行调整。