文巾解题 5. 最长回文子串
1 題目描述
2 解題思路
2.1?動態(tài)規(guī)劃
對于一個子串而言,如果它是回文串,并且長度大于 2,那么將它首尾的兩個字母去除之后,它仍然是個回文串。
例如對于字符串 “ababa”,如果我們已經(jīng)知道 首尾元素都是回文串,那么“bab” 一定是回文串。
也就是說,如果 s[i+1:j?1]?是回文串,并且?s[i]=s[j],那么s[i:j] 是回文串。
上文的所有討論是建立在子串長度大于 2?的前提之上的,我們還需要考慮動態(tài)規(guī)劃中的邊界條件,即子串的長度為 1?或 2。
對于長度為 1?的子串,它顯然是個回文串。
對于長度為 2 的子串,只要它的兩個字母相同,它就是一個回文串。
因此我們就可以寫出動態(tài)規(guī)劃的邊界條件:
根據(jù)這個思路,我們就可以完成動態(tài)規(guī)劃了,最終的答案即為所有P(i,j)=true 中j?i+1(即子串長度)的最大值。
class Solution:def longestPalindrome(self, s: str) -> str:n=len(s)if(len(s)<2):return s#如果字符串有一個或者零個元素,那么這個字符串肯定是回文串maxLen=1 #最長回文子串的長度begin=0#最長回文子串的起始位置dp=[[False]*n for _ in range(n)]#dp是一個n*n的數(shù)組,dp[i][j]表示[i,j]部分的s是不是回文串for i in range(n):dp[i][i]=True#[i,i]部分(也就是子串長度為1)一定是回文串for L in range(2,n+1):#從小到大枚舉子串的長度(長度為1的都是True,前面已經(jīng)考慮過了)for i in range(n):#遍歷起始位置j=i-1+L#j-i+1=L -> j=i-1+L#我們目前考慮的字串的終止位置if(j>=n):break #如果終止位置超過邊界了,那么我們就考慮更長一格的字符串,再從坐標0開始考慮; #當前字符串長度停止繼續(xù)遍歷起始位置(因為之后起始位置對應的終止位置也是越界的) #因為我們是左閉右閉,所以終止條件是j≥n而不是j>nif(s[i]!=s[j]):pass#如果起止元素不相等,那么[i,j]不是回文串else:if(L==2 or L==3):dp[i][j]=True #如果此時我們考慮的字符串長度是2或者3,那么起止元素相等后, #中間只”夾“著零個或者一個元素,那么此時[i,j]是回文數(shù)else:dp[i][j]=dp[i+1][j-1]#不然的話,[i,j]是不是回文數(shù)取決于[i+1,j-1]是不是回文數(shù)if(dp[i][j]==True and L>maxLen):maxLen=Lbegin=i #如果此時我們遍歷到的回文子串長度比目前為止遍歷到的回文子串長, #那么更新此時的回文子串起始位置和長度return s[begin:begin+maxLen]?
?
2.2? 中心擴展
我們觀察一下2.1中的狀態(tài)轉(zhuǎn)移方程
我們可以看到其中的狀態(tài)轉(zhuǎn)移鏈:
可以發(fā)現(xiàn),所有的狀態(tài)在轉(zhuǎn)移的時候的可能性都是唯一的。也就是說,我們可以從每一種邊界情況開始「擴展」,也可以得出所有的狀態(tài)對應的答案。
邊界情況即為子串長度為 1或 2?的情況。我們枚舉每一種邊界情況,并從對應的子串開始不斷地向兩邊擴展。如果兩邊的字母相同,我們就可以繼續(xù)擴展,例如從 P(i+1,j?1) 擴展到 P(i,j);如果兩邊的字母不同,我們就可以停止擴展,因為在這之后的子串都不能是回文串了。
我們枚舉所有的長度為1或者2并嘗試「擴展」,直到無法擴展為止,此時的最長回文串即是最終的答案。
class Solution:def expand_around_center(self,s,left,right):l=len(s)while(left>=0 and right<=l-1 and s[left]==s[right]): #如果此時子串的左邊界和右邊界沒有越界,而且我們此時左邊界和右邊界的值是相等的 #那么我們將考慮的子串向外擴張“一圈”,繼續(xù)討論。如此往復,直到至少不滿足這三個條件的一個left=left-1right=right+1return(left+1,right-1) #因為我們最后考慮的左右邊界是至少不滿足三個條件之一的, #所以我們左邊界右邊界要向內(nèi)“縮一格”,此時的子串是我們當前擴展到的最大回文串def longestPalindrome(self, s: str) -> str:start=0end=0#start,end是我們最長回文子串的起止位置l=len(s)for i in range(l):#遍歷所有初始回文子串的左邊界left1,right1=self.expand_around_center(s,i,i+1)left2,right2=self.expand_around_center(s,i,i)if(right1-left1>end-start):end=right1start=left1if(right2-left2>end-start):end=right2start=left2return(s[start:end+1])?
總結(jié)
以上是生活随笔為你收集整理的文巾解题 5. 最长回文子串的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文巾解题 1046. 最后一块石头的重量
- 下一篇: pytorch笔记:实现简易LSTM