给定一个字符串S,找到S中最长的回文子串。假设S的最大长度为1000.
示例1:
输入‘babad' 输出’bab', 注意aba也是一个有效的答案
输入‘cbbd' 输出’bb'
解题思路:
1.中心扩展算法:遍历每一个索引,以这个索引为中心,利用回文串中心对称的特点,向两边扩散,看最多能扩散多远。
也要考虑回文串的奇偶
def spread(s,size,left,right):
# l=left
# r=right
while left>=0 and right<size and s[left]==s[right]:
left-=1
right+=1
return s[left+1:right],right-left-1
def center_spread(s):
m=len(s)
if m==0:
return ''
logest_len=1
logest_str=s[0]
for i in range(m):
oddstr,oddlen=spread(s,m,i,i)
evenstr,evenlen=spread(s,m,i,i+1)
maxstr=oddstr if oddlen>evenlen else evenstr
if len(maxstr)>logest_len:
logest_len=len(maxstr)
logest_str=maxstr
return logest_str
if __name__=="__main__":
# s='ababa'
# s='babad'
s='cbbbbbdd'
str=center_spread(s)
print(str)
2.动态规划算法:用s[i,j]表示在区间[i,j]的字符串,p[i,j]表示s[i,j]是否是回文串,当p[i,j]为true的时候,p[i+1,j-1]也必定为true,那么s[j]与s[i]也相等。其中要保证区间[i+1,j-1]可以形成区间,即i+1<j-1——》j-i>2.
实现细节:因为要构成子串 i一定小于等于 j ,我们只关心 “状态”数组“下三角”的那部分取值。理解上面的“状态转移方程”中的 (i>= j - 2 or p[i+1][j-1]) 这部分是关键。
def dynamiclogest(s):
size=len(s)
if size<=1:
return s
p=[[False for _ in range(size)]for _ in range(size)]
longeststr=s[0]
longest=1
for j in range(size):
for i in range(j):
if s[i]==s[j] and(j-i<=2 or p[i+1][j-1]):
p[i][j]=True
if j-i+1>longest:
longest=j-i+1
longeststr=s[i:j+1]
return longeststr
if __name__=="__main__":
# s='ababa'
# s='babad'
s='cbbbbbdd'
str=dynamiclogest(s)
print(str)
3利用最长公共子串求解:反转 S,使之变成 S' 。找到 SS 和 S'S之间最长的公共子串,这也必然是最长的回文子串。
例如,S = “caba”, S ′ =“abac”:之间的最长公共子串为aba”,恰恰是答案。
当S=“abacdfgdcaba”, S ′=“abacdgfdcaba”:之间的最长公共子串为 “abacd”。显然,这不是回文。
我们可以看到,当 SS 的其他部分中存在非回文子串的反向副本时,最长公共子串法就会失败。为了纠正这一点,每当我们找到最长的公共子串的候选项时,都需要检查子串的索引是否与反向子串的原始索引相同。如果相同,那么我们尝试更新目前为止找到的最长回文子串;如果不是,我们就跳过这个候选项并继续寻找下一个候选。
def longestPalindrome(s):
s_inverse = s[::-1]
max = 0
maxStr = ""
if len(s) < 2:
return s
for start in range(len(s)):
for end in range(start + 1, len(s) + 1):
if s.count(s_inverse[start:end]) > 0:
#count()函数是在字符串s中查找符合条件的s_inverse[start:end]字符串的个数
index = s.index(s_inverse[start:end])
#index()函数是在字符串s中查找符合条件s_inverse[start:end]的子字符串的首索引位置。
#子串索引index,反向子串索引start_inverse
# print(index)
start_inverse = len(s) - end
# print(start_inverse)
if (end - start > max) and (index == start_inverse):
max = end - start
maxStr = s_inverse[start:end]
#print('******************')
return maxStr
if __name__=="__main__":
s='ababa'
# s='babad'
str=longestPalindrome(s)
print(str)