返回
小兵出招,教你一行代码搞定最长回文子串!
前端
2023-12-01 07:44:25
最长回文子串的定义
回文子串是指从左到右读和从右到左读都是一样的子串。例如,“abba”是一个回文子串,而“abc”不是。最长回文子串是指字符串中最长的回文子串。
Manacher算法
Manacher算法是一种解决最长回文子串问题的经典算法。该算法的基本思想是将每个字符作为一个回文子串的中心,然后向两边扩展,直到找到一个回文子串。
Manacher算法的步骤
- 在字符串的两端添加特殊字符“$”。
- 定义一个数组P,其中P[i]表示以第i个字符为中心的回文子串的长度。
- 初始化P[1]为1,P[2]为2。
- 从i = 3开始,依次计算P[i]。对于每个i,先找到最大的j,使得j < i且P[i - j - 1] <= j。然后,令P[i] = P[i - j - 1] + 2 * (i - j) + 1。
- 找到P[i]的最大值,并记录下对应的回文子串。
KMP算法
KMP算法是另一种解决最长回文子串问题的经典算法。该算法的基本思想是利用一个失败函数来快速跳过不匹配的字符。
KMP算法的步骤
- 预处理字符串,计算出失败函数。
- 从字符串的第一个字符开始,依次与失败函数中的值进行比较。
- 如果当前字符与失败函数中的值匹配,则向右移动一位。
- 如果当前字符与失败函数中的值不匹配,则根据失败函数的值跳过不匹配的字符。
- 重复步骤3和4,直到到达字符串的末尾。
- 记录下最长的匹配子串。
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))