关于回文的常见题目

1、最长回文子串

这道题要好好说一下,做了好几次了,做完过一段时间又忘了,所以总结一下,以后忘得时候拿出来看,用两种比较好理解的方法来做

先上动态规划的代码

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if not s:
            return ''
        n = len(s)
        maxlen = 0
        res = 0
        dp = [[False for _ in range(n)]for _ in range(n)]
        for j in range(n):
            for i in range(j+1):
                dp[i][j] = s[i]==s[j] and (j-i<=2 or dp[i+1][j-1])
                if dp[i][j]:
                    if j-i+1>maxlen:
                        maxlen = j-i+1
                        res = s[i:j+1]
        return res

以s = ' babad' 为例,j不断地向后,i是从0到j,不断地去判断,所以两层for循环是写成代码里那样,当j=4时,i从0到4,然后去查找最长回文

当然,两层for循环还有其他的写法,图片来自来源

image.png

dp[i][j] 表示的是 s[i] 和 s[j] 是否相等,如果相等,并且 dp[i+1][j-1] 也相等,说明之前是回文子串,然后再加上现在这两个。所以dp[i][j] = s[j] == s[j] && dp[i+1][j-1],但是看代码发现还有 j - i <=2 这个选项,原因如下:

s = ' babad' ,当 i =0 ,j=2的时候,j-i=2,并且 s[j] == s[j],中间只剩一个元素a肯定是回文,所以就不需要判断 dp[i+1][j-1],直接就是对的。

而且 j - i <= 2 要写在  dp[i+1][j-1]前面,否则会报错,因为当 i=1,j=2时,如果先写 dp[i+1][j-1] ,那么i 变成2,j变成1,这样从刚才的分析来说是不对的,因为j是不断地向后,而i是从0到 j的,i 就超出 j了,所以是不行的。其他的部分比较好懂就不解释了

第二种方法:

class Solution:
    def __init__(self):
        self.res = ''
    def longestPalindrome(self, s: str) -> str:
        if not s:
            return ''
        for i in range(len(s)):
            self.helper(s,i,i)
            self.helper(s,i,i+1)
        return self.res
    def helper(self,s,left,right):
        while left>=0 and right<len(s) and s[left]==s[right]:
            left-=1
            right+=1
        cur = s[left+1:right]
        if len(cur)>len(self.res):
            self.res = cur 

这种方法采取的是中心扩散法

从中间向两边扩散,但是字符串的长度可能是奇数,可能是偶数,所以直接写两次,结果是一样的

2.最长回文子序列

先上代码

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        if not s:
            return 0
        n = len(s)
        dp = [[0 for _ in range(n)]for _ in range(n)]
        for i in range(n):
            dp[i][i] = 1
        for i in range(n-1,-1,-1):
            for j in range(i+1,n):
                if s[i]==s[j]:
                    dp[i][j] = dp[i+1][j-1]+2
                else:
                    dp[i][j] = max(dp[i][j-1],dp[i+1][j])
        return dp[0][n-1]

核心代码是下文,其实还比较好理解,如果两端的字母相同,那长度加2,否则就看两边子串的长度,取最长的那个

if s[i]==s[j]:
    dp[i][j] = dp[i+1][j-1]+2          
else:
    dp[i][j] = max(dp[i][j-1],dp[i+1][j])
                   

对于两个for循环,第一个for循环是从后面往前来设置i的位置,假如字符串是 "bbbab" ,当 i 指向第2个位置的时候,j从第3个开始依次向后和第i个位置的字母进行比较

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值