背景; 求解字符串最长回文长度。
尝试方法: 暴力遍历,马拉车(中心扩散法)
# -*- coding: utf-8 -*-
"""
Created on Tue Mar 17 19:55:45 2020
@author: Administrator
"""
## 回文串是连续的子串,从左读和从右读顺序一样
class Solution(object):
"""暴力方法:遍历所有子串比较繁琐"""
## 初始版本, 太多多余定义
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
m=0 # 当前子串初始长度
max_len=0 #最大回文子串初始长度
max_plaind=''
for i in range(len(s)):
m=i+1 ##当前子串的长度
str1='' ## 当前子串
flag=0
for j in range(len(s)):
if m<=len(s) and (j+m<=len(s)): ##子串长度不能大于最长,子串右边位置不能超过边界
str1=s[j:j+m] ## 当前子串
if str1==str1[:: -1]: ## 判断正读和反读是否一样
flag=1
if flag==1 and len(str1)>max_len:
max_len=len(str1)
max_plaind=str1
else:
break
return max_plaind
""" 暴力方法: 代码缩减后,第一层子串个数,第二层子串开始位置"""
def longestPalindrome1(s):
"""
:type s: str
:rtype: str
"""
m=0 # 当前子串初始长度
max_len=0 #最大回文子串初始长度
max_plaind=''
if s==s[:: -1]:
return s
for i in range(len(s)-1):
m=i+1
for j in range(len(s)-m+1):
print str(m)+' '+str(j+m)+' '+ s[j:j+m]+' '+s[j:j+m][::-1]
if m>max_len and j+m<=len(s) and s[j:j+m]==s[j:j+m][::-1]: ##子串长度不能大于最长,子串右边位置不能超过边界
max_len=m
max_plaind=s[j:j+m]
return max_plaind
""" 暴力方法: 代码缩减后,第一层,子串开始位置, 第二层,子串长度"""
## 注意切片时得+1,因为n:m, 实际取的是n:m-1
def otheran(s):
max_len=1 ##最大回文子串长度
max_plaind='' # 最大回文子串
if s==s[::-1]:
return s
else:
for i in range(len(s)-1):
for j in range(i+1,len(s)):
if j-i>max_len and s[i:j+1]==s[i:j+1][::-1]:
max_len=j-i
max_plaind=s[i:j+1]
return max_plaind
"""马拉车--Manacher算法,参考别人的"""
##这是一个复杂度为 O(n) 的 Manacher(马拉车) 算法。
##假如字符串是奇数个,那么我们可以通过遍历所有字符串,再对所有字符串进行左右匹配,就像中心扩散方法一样。然后得到长度最大的字符串
##但是如果字符串是偶数个,我们无法进行此操作
##这个算法的最终要的额一点就是,我们将一个偶数长/奇数长的字符串,构造成新的字符串。
##这样我们可以对新字符串的每个字符,进行左右匹配。
##以每个字符为中心,开始向两边按step=1,向两边扩充,下次迭代条件,左右都没有越界,且左右相等。
##其次,每次扩充后新的回文与旧回文做比较,更新最大回文字符串。
## 回文字符串起始位置 start=(i-max_len)//2 ,其中,i表示当前中心所在位置
def manacherTest(s):
if str(len(s))<2:
return s
max_len=0
"""因为要想中心扩散,字符串是奇数可以中心扩散,但是偶数的话不能中心扩散,因此对字符串做处理"""
test="#"+"#".join(s)+'#' ## 奇数需要偶数个填充,偶数需要奇数个填充
"""以第二个字符开始,因为第一个左边是空的,不需要扩散"""
for i in range(len(test)):
left=i-1 # 左扩散
right=i+1 #右扩散
step=0 ## 初始化步长
"""以i为中心开始扩散,扩散条件,等步长扩散后,左右不越界,且左边等于右边"""
#print("spread",'i='+str(i),'left:'+test[left],test[i],'right:'+test[right],left,right)
while left>=0 and right<len(test) and test[left]==test[right]:
print("----in spread",'left:'+test[left],'right:'+test[right],step,i,left,right)
left=left-1
right=right+1
step=step+1
if step>max_len:
max_len=step
start=(i-max_len)//2 ##确定起始位置, '//'向下取整 (i-max_len)//2,减去回文得到回文起始位置,再除2,得到起始位置
print(i,step)
return s[start:start+max_len]