1.中心扩展算法
事实上,只需使用恒定的空间,我们就可以在 O(n2) 的时间内解决这个问题。
我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n - 1 个这样的中心。
你可能会问,为什么会是 2n - 1 个,而不是 n 个中心?原因在于所含字母数为偶数的回文的中心可以处于两字母之间(例如 “abba” 的中心在两个 ‘b’ 之间)。
class Solution:
def longestPalindrome(self, s: str) -> str:
"""
定义一个检查函数,
如果可以向两边扩展那么左右索引各自加一
否则输出此中心的最大回文长度
"""
def expandaroundcenter(s:str,l:int,r:int)->int:
while(l>=0 and r<len(s) and s[l]==s[r]):
l-=1
r+=1
"此处是减1,而不是加1,因为l,r是在判断后加的1"
return r-l-1
end=start=0
for i in range(len(s)):
"判断以i为中心的奇数长度"
len1=expandaroundcenter(s,i,i)
"判断以i,i+1为中心的偶数长度"
len2=expandaroundcenter(s,i,i+1)
maxlen= len1 if len1>len2 else len2
if(maxlen>end-start):
"""
此处需要减一,因为我们使用了取整,比如baab,maxlen=4
start==1-(4-1)//2==0
"""
start=i-(maxlen-1)//2
end=i+maxlen//2
return s[start:end+1]
2.动态规划算法
动态规划与递归类似都把问题分解为子问题,DP适合子问题重叠,最优化方法.
分析问题过程如下
1.分析问题空间
2.建立递归式(状态转移方程)
3.自底向上计算
4.记录最优方案的详细过程(可选)
在这个问题中,我们可以用到上一次的子问题
1.
设P(i,j)为s[i,j]是否为回文子串,是的话为True,否则为False
2.
可以得出 P(i,j)=True if s[i]==s[j] and P(i+1,j-1)
这就是状态转移方程,OK 问题得解.
3.
从l=0 ->len(s) 分别计算子问题
4.
把结果记录在s[i,j+1]
class Solution:
def longestPalindrome(self, s: str) -> str:
t=len(s)
if(t==0 or t==1):
return s
#建立二维数组
p=[[False for i in range(t)] for i in range(t)]
maxlen=0
#子问题从0 开始
for l in range(t):
#注意i的索引范围
for i in range(t-l):
j=i+l
if(s[i]==s[j] and (l<2 or p[i+1][j-1])):
p[i][j]=True
if(l+1>maxlen):
maxlen=l+1
ans=s[i:j+1]
return ans
另一种动态递归方法
利用的是上一次计算的最大长度
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
if len(s) < 2 or s == s[::-1]:
return s
n = len(s)
start, maxlen = 0, 1
for i in range(1, n):
odd = s[i - maxlen - 1:i + 1]
#
even = s[i - maxlen:i + 1]
#e.g cbabd i=3时 maxlen=1
if i - maxlen - 1 >= 0 and odd == odd[::-1]:
start = i - maxlen - 1
maxlen += 2
continue
# e.g. bbbbbb i=3 时 maxlen=3
if i - maxlen >= 0 and even == even[::-1]:
start = i - maxlen
maxlen += 1
return s[start:start + maxlen]