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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值