该问题是力扣上一道中等难度的题目,但是方法却有多样,值得记录一下。题干如下:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
下面给出三种方法:暴力解法,中心扩散和动态规划。
首先想到的就是无脑的暴力解法,从左到右遍历,记初始的一个字符串长度为 1 ,当遍历找到一个回文子串时,字符串的长度加一,不断增加知道找不到该长度的回文子串。这个方法比较好想出来,但是由于遍历的原因,时间复杂度较高,运算的时间也就较高。
判断是否为回文子串的方法是分两种情况:
字符串长度 n 为奇数,0 到 n − 1 2 \frac{n-1}{2} 2n−1与 n + 1 2 \frac{n+1}{2} 2n+1 到 n 的子串是倒置的关系,只需要判断一下即可验证是否为回文数串;
字符串长度 n 为偶数,将字符串分为等距两段,判断是否为倒置关系。
其代码如下:
def judge_Palindrome(s):
if len(s) % 2 == 1: # odd
if s[0:int(len(s) / 2)] == s[:int(len(s) / 2):-1]:
return True
else:
return False
elif len(s) % 2 == 0: # even
if s[0:int(len(s) / 2)] == s[-1:-int(len(s) / 2) - 1:-1]:
return True
else:
return False
接下来的思路就同一开始说的一样,遍历即可:
if len(s) < 2:
l = s
else:
l = s[0]
i = 2
while i <= len(s):
for start_node in range(0, len(s) - i + 1):
if judge_Palindrome(s[start_node:start_node + i]):
l_longest = i
l = s[start_node:start_node + i]
break
else :
continue
i = i + 1
同样是从左向右遍历,以每个元素为一个中心,左右扩散到可以满足的最长回文串结束。
def center_spread(s, size, left, right):
i = left
j = right
while i >= 0 and j < size and s[i] == s[j]:
i -= 1
j += 1
return s[i + 1:j], j - i - 1
if len(s) < 2:
l = s
else :
max_len = 1
l = s[0]
for i in range(len(s)):
l_odd, odd_len = center_spread(s, len(s), i, i)
l_even, even_len = center_spread(s, len(s), i, i + 1)
# find the current maximum length
cur_max_l = l_odd if odd_len > even_len else l_even
if len(cur_max_l) > max_len:
max_len = len(cur_max_l)
l = cur_max_l
关键有两点:
定义“状态”
d p [ l ] [ r ] dp[l][r] dp[l][r]表示子串 s [ l , r ] s[l, r] s[l,r](包括区间左右端点)是否构成回文串,是一个二维布尔型数组。即如果子串 s [ l , r ] s[l, r] s[l,r] 是回文串,那么 d p [ l ] [ r ] = T r u e dp[l][r] = True dp[l][r]=True。
找到“状态转移方程”
dp[l, r] = (s[l] == s[r] and (r - l <= 2 or dp[l + 1, r - 1]))
当 s [ l , r ] s[l,r] s[l,r]是回文字串时,毋庸置疑, s [ l + 1 , r − 1 ] s[l+1,r-1] s[l+1,r−1]也是回文字串,唯一注意的是,当 s [ l + 1 , r − 1 ] s[l+1,r-1] s[l+1,r−1]只有1个或者没有元素的时候,是无法用dp判断的,但是此时一定是回文字串,因为 s [ l ] = s [ r ] s[l] = s[r] s[l]=s[r]。
下面给出代码:
size = len(s)
if size < 2:
res = s
else :
dp = [[False for _ in range(size)] for _ in range(size)]
longest_l = 1
res = s[0]
for r in range(1, size):
for l in range(size):
if s[l] == s[r] and (r - l <= 2 or dp[l + 1][r - 1]):
dp[l][r] = True
cur_len = r - l + 1
if cur_len > longest_l:
longest_l = cur_len
res = s[l:r + 1]
− − − − − − − − − − − − − − − − ---------------- −−−−−−−−−−−−−−−−
该文章首发于 zyairelu.cn
欢迎来到我的网站进行评论及研讨
个人邮箱[email protected]
− − − − − − − − − − − − − − − − ---------------- −−−−−−−−−−−−−−−−