方法一:暴力解法
把一个字符串中的所有子字符串提取出来
把每个子字符串分别验证是否为回文字符串
class Solution:
def func(self,s:str):
max_len = 0
res = None
n = len(s)
for i in range(n-1):
for j in range(i+1,n):
if self.val_plalindrome(s,i,j) and len(s[i:j+1])>=max_len:
max_len = len(s[i:j+1])
res = s[i:j+1]
return res
def val_plalindrome(self,s,left,right):
while left < right:
if s[left] != s[right]:
return False
left+=1
right-=1
return True
s='dddddabadeeeseq'
so = Solution()
res = so.func(s)
print(res) #dabad
复杂度分析:
时间复杂度:O(N^3),N是字符串的字符个数.上面的代码枚举子字符串用了2次for循环,为N^2,然后验证又遍历了一次,所以是N^3
空间复杂度:O(1),只使用到常数个临时变量,与字符串长度无关。
法二:动态规划
动态规划的特点是:把大问题化成小问题解决,这个网页讲得非常清楚且生动:https://www.cnblogs.com/cthon/p/9251909.html
算法:
回文字符串长度有可能是奇数,也有可能是偶数。
动态规划的思想很简单,应用在回文数检测时,例如:aa是回文的,然后判断XaaY时,只需要X=Y,那么XaaY就也是回文字符串。同理 :有 XbY,当X=Y时,其也是回文的。那么动态规划的思想其“大事化小”的思想就体现了。所有字符串都通过从其最小的子字符串开始判断。
-------------------------------------
在动态规划中,有三个概念很重要:
1.最优子结构:
设S为一个字符串。用dp[2,8] 表示S字符串的[2位到8位]的子字符串 。当dp[2,8] = True时,其为回文字符串。
则:dp[3,7]且S[2] = S[8]时,dp[2,8] = True。所以对于dp[2,8]而言dp[3,7]为其最优子结构,因为dp[2,8]的值是由dp[3,7]决定的。
2.边界:
例如求dp[2,9]是否回文串,它的边界就是其最中间两个相邻子字符串dp[5,6].
3.状态转移方程:
若满足:S[i]==S[r] and dp[i+1][r-1] == True,则dp[i][j] = True。这为状态转移方程。预示着这个问题的一般性规律。
class Solution:
def longestPalindrome(self, s: str) -> str:
if(not s or len(s)==1):
return s
n=len(s)
dp=[[False]*n for _ in range(n)]
max_len=1
start=0
for i in range(n):
dp[i][i]=True
if(i<n-1 and s[i]==s[i+1]):
dp[i][i+1]=True
start=i
max_len=2
for l in range(3,n+1):
for i in range(n+1-l):
r=i+l-1
if(s[i]==s[r] and dp[i+1][r-1]):
dp[i][r]=True
start=i
max_len=l
return s[start:start+max_len]
s='dddddabadeeeseq'
so = Solution()
res = so.longestPalindrome(s)
print(res) #dabad
复杂度分析:
时间复杂度:O(n^2) :因为如上面代码所示,第一个循环空间复杂度是n,第二个循环是2个嵌套的循环,所以是n^2,所以总的是(n+n^2),所以是O(n^2)
空间复杂度:O(n^2):第一个循环中,开辟的dp二维数组大小为n^2
第三,中心扩展法
过程:设输入字符串为S,首先遍历S中的每一个字符,然后以该字符为中心,向外扩展,寻找以该字符为中心的长度最长的回文字符串。
class Solution:
def longestPalindrome(self, s: str) -> str:
def expand(l,r): #返回以某点为中心的最长回文字符串
while(0<=l and r<n and s[l]==s[r]):
l-=1
r+=1
return r-l-1
if(not s or len(s)==1):
return s
n=len(s)
start=0
end=0
for i in range(n):
len1=expand(i,i)
len2=expand(i,i+1)
len_long=max(len1,len2)
if(len_long>end-start):
start=i-(len_long-1)//2
end=i+(len_long)//2
return s[start:end+1]
s='dddddabadeeeseqd'
so = Solution()
res = so.longestPalindrome(s)
print(res) #dabad
时间复杂度:
O(n^2),n为输入字符串S的长度。因为expand方法中一个循环花费时间O(n),主循环中也调用了2次expand,所有花费了时间 (2*n^(2)),所以时间复杂度为O(n^2)
空间复杂度:
O(1)