最長回文子串以及 Manacher 演算法

2021-09-16 12:04:59 字數 3959 閱讀 2378

正如孔乙己知道「回」字有四種寫法

這個問題也有四種解決的方法

暴力法列舉這個字串的所有子串,再判斷是否為回文。時間複雜度為 o(n^3)

此處不實現,太弱智了

中心擴充套件法

從字串的每乙個字元開始,以此為中心,向兩側擴充套件,直到不是回文為止。

這種方法的時間複雜度是 o(n^2)。但是要考慮到許多特殊情況。如 bb,abbbb,bbbb 等偶數個的回文,所以邏輯上比較複雜。使用這種方法打敗了接近 50% 的 python 提交。

def

longestpalindrome

(self, s)

:"""

:type s: str

:rtype: str

"""r =

''for i in

range(0

,len

(s))

: temp = s[i]

j = i -

1 k = i +

1while j >=

0and k <

len(s)

and s[j]

== s[k]

: temp = s[j]

+ temp + s[k]

j -=

1 k +=

1# 識別如 abba 這種的回文

if k <

len(s)

and k == i +

1and s[k]

== s[i]

: temp += s[k]

j = i -

1 k +=

1while j >=

0and k <

len(s)

and s[j]

== s[k]

: temp = s[j]

+ temp + s[k]

j -=

1 k +=

1# 識別如 aabbbbaa 這種回文if1

< k <

len(s)

and s[k]

== s[i]

and temp.count(s[i])==

len(temp)

: temp += s[k]

k +=

1while j >=

0and k <

len(s)

and s[j]

== s[k]

: temp = s[j]

+ temp + s[k]

j -=

1 k +=1if

len(temp)

>

len(r)

: r = temp

return r

動態規劃法

假設 dp[i, j] = 1 表示 s[i…j] 為回文,則有 dp[i, j] = 1 —> dp[i+1, j-1] = 1

所以得到狀態轉移方程

d p[

i,j]

=dp[i+1, j-1], & \text \\ 0, &\text \end

dp[i,j

]={d

p[i+

1,j−

1],0

,​s[i] = s[j]s[

i]!=s

[j]​

dp 陣列的初始化

dp[i,i] = 1

dp[i,i+1] = 1 if s[i] == s[i+1]

def

longestpalindrome

(self, s)

:"""

:type s: str

:rtype: str

"""ifnot s or

len(s)==1

:return s

dp =[[

false

for j in

range

(len

(s))

]for i in

range

(len

(s))

] longest =

1 start =

0# 初始化 dp

for i in

range(0

,len

(s))

: dp[i]

[i]=

true

if i +

1<

len(s)

and s[i]

== s[i+1]

: dp[i]

[i+1]=

true

start = i

longest =

2for l in

range(3

,len

(s)+1)

:# 列舉子串長度

for i in

range(0

,len

(s)- l +1)

:# 列舉子串的起始點

j = l + i -

1if s[i]

== s[j]

and dp[i+1]

[j-1]:

dp[i]

[j]=

true

start = i

longest = l

return s[start: start + longest]

manacher 演算法

該演算法的介紹在

以下是其用 python 的實現( faster than 93.25% of python online submissions )

def

longestpalindrome

(self, s)

:"""

:type s: str

:rtype: str

"""ifnot s or

len(s)==1

:return s

t ='$#'

+'#'

.join(s)

+'#'

p =[0

]*len(t)

# p[i] 表示以 t[i] 為中心的回文的最大半徑

mx =0id

=0reslen =

0# 記錄全域性最大的半徑

rescenter =

0for i in

range(1

,len

(t))

: p[i]

=min

(p[2*id

- i]

, mx - i)

if mx > i else

1while i + p[i]

<

len(t)

and i - p[i]

>=

0and t[i + p[i]

]== t[i - p[i]]:

p[i]+=1

if mx < i + p[i]-1

: mx = i + p[i]-1

id= i

if reslen < p[i]

: reslen = p[i]

rescenter = i

return s[

(rescenter - reslen)//2

:(rescenter - reslen)//2

+ reslen -

1]

高效的求最長回文子串的演算法 Manacher

gdoi市選出了一道關於manacher的題目,於是打算學一下,但因為網路流鴿了一陣,最近才學完,學完後表示複雜度有點迷。manacher,俗稱馬拉車,是由一位名叫manacher的人與1975年提出的,這個演算法讓求最長回文子串的複雜度從o n 2 下降到了o n 先從n方演算法說起,n方演算法是...

最長回文子串 最長回文子串行

1.最長回文子串行 可以不連續 include include include include using namespace std 遞迴方法,求解最長回文子串行 intlps char str,int i,int j intmain include include include using n...

最長回文子串

描述 輸入乙個字串,求出其中最長的回文子串。子串的含義是 在原串連續出現的字串片段。回文的含義是 正著看和倒著看是相同的,如abba和abbebba。在判斷是要求忽略所有的標點和空格,且忽略大小寫,但輸出時按原樣輸出 首尾不要輸出多餘的字串 輸入字串長度大於等於1小於等於5000,且單獨佔一行 如果...