leetcode--------找出字符串中最长的回文字符串

方法一:暴力解法

把一个字符串中的所有子字符串提取出来

把每个子字符串分别验证是否为回文字符串

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)

发布了270 篇原创文章 · 获赞 408 · 访问量 76万+

猜你喜欢

转载自blog.csdn.net/u014453898/article/details/104507615