📅  最后修改于: 2023-12-03 15:22:34.550000             🧑  作者: Mango
在字符串处理中,最长回文子串(Longest Palindromic Substring)是一个常见的问题。其定义为一个字符串中最长的回文子串,即该子串从左往右和从右往左读是相同的。
要解决这个问题,我们需要先了解回文串的特点:以回文串中心位为轴,从中心展开,两端的字符是相同的。因此,我们可以枚举每个可能的中心位,分别向左右两侧扩展,判断扩展后的子串是否是回文串,然后取最长的回文子串即可。
具体实现时有两种情况:
1.字符串长度为奇数,中心位是一个字符。例如:abcdefg
的中心位是 d
。
def findLongestPalindrome(s: str) -> str:
n = len(s)
res = ""
# 中心位是一个字符
for i in range(n):
# 向左右两侧扩展
l, r = i, i
while l >= 0 and r < n and s[l] == s[r]:
l -= 1
r += 1
substring = s[l + 1:r]
if len(substring) > len(res):
res = substring
return res
2.字符串长度为偶数,中心位是两个相邻字符的中间位置。例如:abcd1234dcba
的中心位是 34
。
def findLongestPalindrome(s: str) -> str:
n = len(s)
res = ""
# 中心位是相邻的两个字符之间
for i in range(n):
# 向左右两侧扩展
l, r = i, i + 1
while l >= 0 and r < n and s[l] == s[r]:
l -= 1
r += 1
substring = s[l + 1:r]
if len(substring) > len(res):
res = substring
return res
上面的算法时间复杂度为 $O(n^2)$,可以通过动态规划来进行优化,将时间复杂度降到 $O(n)$。这个算法涉及到了一个二维数组 $dp$,其中 $dp[i][j]$ 表示从下标 $i$ 到下标 $j$ 的子串是否是回文串。根据回文串的定义,只需要判断 $dp[i+1][j-1]$ 是否是回文串即可。转移方程为:
$$ \begin{cases} dp[i][j]=1 & \text{if }s_i=s_j \ dp[i][j]=0 & \text{if }s_i\neq s_j \end{cases} $$
def findLongestPalindrome(s: str) -> str:
n = len(s)
res = ""
# 构建二维数组
dp = [[0] * n for _ in range(n)]
# base case(处理长度为 1 和 2 的子串)
for i in range(n):
dp[i][i] = 1
if i < n - 1 and s[i] == s[i + 1]:
dp[i][i + 1] = 1
res = s[i:i + 2]
# 状态转移
for i in range(n - 3, -1, -1):
for j in range(i + 2, n):
if s[i] == s[j] and dp[i + 1][j - 1]:
dp[i][j] = 1
if j - i + 1 > len(res):
res = s[i:j + 1]
return res
最长回文子串是一个比较基础的问题,在面试中也经常被提到。通过掌握回文串的特点,考虑动态规划的状态转移方程,我们可以轻松解决这个问题。