python练习题,本题学习的知识点:
1.range(n,m)范围是n~m-1
2.申请一个数组
L = [0] * N 申请一个N长度的Int数组,并初始值赋值为0
以下为本题解法:
O(n)时间复杂度方法——Manacher算法 转载自:https://blog.youkuaiyun.com/qq_32354501/article/details/80084325
1.思想:
1)将原字符串S的每个字符间都插入一个永远不会在S中出现的字符(本例中用“#”表示),在S的首尾也插入该字符,使得到的新字符串S_new长度为2*S.length()+1,保证Len的长度为奇数(下例中空格不表示字符,仅美观作用);
例:S: a a b a b b a
S_new: # a # a # b # a # b # b # a #
2)根据S_new求出以每个字符为中心的最长回文子串的最右端字符距离该字符的距离,存入Len数组中,即S_new[i]—S_new[r]为S_new[i]的最长回文子串的右段(S_new[2i-r]—S_new[r]为以S_new[i]为中心的最长回文子串),Len[i] = r - i + 1;
S_new: # a # a # b # a # b # b # a #
Len: 1 2 3 2 1 4 1 4 1 2 5 2 1 2 1
Len数组性质:Len[i] - 1即为以Len[i]为中心的最长回文子串在S中的长度。在S_new中,以S_new[i]为中心的最长回文子串长度为2Len[i] - 1,由于在S_new中是在每个字符两侧都有新字符“#”,观察可知“#”的数量一定是比原字符多1的,即有Len[i]个,因此真实的回文子串长度为Len[i] - 1,最长回文子串长度为Math.max(Len) - 1。
3)Len数组求解(线性复杂度(O(n))):
a.遍历S_new数组,i为当前遍历到的位置,即求解以S_new[i]为中心的最长回文子串的Len[i];
b.设置两个参数:sub_midd = Len.indexOf(Math.max(Len)表示在i之前所得到的Len数组中的最大值所在位置、sub_side = sub_midd + Len[sub_midd] - 1表示以sub_midd为中心的最长回文子串的最右端在S_new中的位置。起始sub_midd和sub_side设为0,从S_new中的第一个字母开始计算,每次计算后都需要更新sub_midd和sub_side;
c.当i < sub_side时,取i关于sub_midd的对称点j(j = 2sub_midd - i,由于i <= sub_side,因此2sub_midd - sub_side <= j <= sub_midd);当Len[j] < sub_side - i时,即以S_new[j]为中心的最长回文子串是在以S_new[sub_midd]为中心的最长回文子串的内部,再由于i、j关于sub_midd对称,可知Len[i] = Len[j];
当Len[j] >= sub.side - i时说明以S_new[i]为中心的回文串可能延伸到sub_side之外,而大于sub_side的部分还没有进行匹配,所以要从sub_side+1位置开始进行匹配,直到匹配失败以后,从而更新sub_side和对应的sub_midd以及Len[i];
d.当i > sub_side时,则说明以S_new[i]为中心的最长回文子串还没开始匹配寻找,因此需要一个一个进行匹配寻找,结束后更新sub_side和对应的sub_midd以及Len[i]。
以下代码解释:
P:当前最长回文串的中心点位置,pl/pr分别代表回文串的左边和右边
L[len]:存储以第k个字符为中心的最长回文串的长度
resultStr:存储最长回文串结果
SS:在原串中添加'#'后的字符串
class Solution:
def longestPalindrome(self, s: str) -> str:
resultStr = ''
ss = '#'
for c in s:
ss = ss + c + '#'
#print(ss)
l = [0] * len(ss)
l[0] = 1
maxl = 0
maxl_final = 0
p = 0
pl = 0
pr = 0
for idx in range(len(ss)):
if idx == 0:
continue
if idx > pr:
ll = 0
while True:
ll+=1
if (idx + ll >= len(ss)) or (ss[idx + ll] != ss[idx - ll]):
ll-=1
break
if ll >= pr - p:
p = idx
pl = p - ll
pr = p + ll
l[idx] = ll
elif idx <= pr:
if pr - idx > l[2 * p - idx]:
l[idx] = l[2 * p - idx]
else:
ll = pr - idx - 1
while True:
ll+=1
if (idx + ll >= len(ss)) or (ss[idx + ll] != ss[idx - ll]):
ll-=1
break
if ll >= pr - p:
p = idx
pl = p - ll
pr = p + ll
l[idx] = ll
#print(p, pl, pr)
#print(l)
for idx in range(pl, pr):
if ss[idx] != '#':
resultStr+=ss[idx]
return resultStr