📅  最后修改于: 2023-12-03 15:10:52.986000             🧑  作者: Mango
在字符串处理中,经常需要判断字符串是否是回文。一种常见的情况是判断一个字符串的两半是否都是回文。本文将介绍如何实现这个功能。
最简单的方法是直接将字符串分为两半,分别判断两半是否都是回文。这个方法的时间复杂度为 $O(n^2)$,因为对于每一个子串都需要判断是否是回文。
def is_palindrome(s):
return s == s[::-1]
def is_half_palindrome(s):
mid = len(s) // 2
left = s[:mid]
right = s[-mid:]
return is_palindrome(left) and is_palindrome(right)
s = 'abcba'
print(is_half_palindrome(s)) # True
这个方法虽然简单,但是时间复杂度比较高,在长字符串上会比较慢。
我们可以采用一种类似于双指针的方法来判断回文。我们从两端同时扫描字符串,如果遇到不同的字符,说明两半不是回文;如果扫描完了整个字符串,说明两半都是回文。
这个方法的时间复杂度为 $O(n)$,是线性级别的,比方法一要快得多。
def is_half_palindrome(s):
left = 0
right = len(s) - 1
while left < right:
if s[left] != s[right]:
return False
left += 1
right -= 1
return True
s = 'abcba'
print(is_half_palindrome(s)) # True
Manacher算法是一个经典的字符串算法,它可以在线性时间内找出一个字符串中的所有回文子串。虽然Manacher算法的时间复杂度比上面的方法要低,但是它的实现过程比较复杂,不适合小白。
def manacher(s):
# 对字符串进行预处理,插入一个不在原字符串中的字符(比如#),
# 这样可以解决奇偶性问题
t = "#" + "#".join(s) + "#"
# 记录以每个字符为中心的最长回文子串的长度
p = [0] * len(t)
max_len = 0
center = 0
for i in range(len(t)):
if i < max_len:
# 如果当前位置在已知的最长回文子串内部,可以利用对称性加速处理
p[i] = min(p[2 * center - i], max_len - i)
else:
p[i] = 1
while i - p[i] >= 0 and i + p[i] < len(t) and t[i - p[i]] == t[i + p[i]]:
p[i] += 1
if i + p[i] > max_len:
max_len = i + p[i]
center = i
return [p[i] - 1 for i in range(len(p))]
def is_half_palindrome(s):
n = len(s)
if n % 2 == 0:
# 如果字符串长度是偶数,先判断左右两半是否相等
if s[:n // 2] != s[n // 2:]:
return False
p = manacher(s)
return all([p[i] >= abs(i - n // 2) for i in range(len(p))])
s = 'abcba'
print(is_half_palindrome(s)) # True
这个方法的时间复杂度为 $O(n)$,比上面的方法还要快一些,但是实现难度比较大。