怎么判断一个字符串的最长回文子串是否在头尾_最长回文字串/子序列问题(leetcode5,9,519)

leetcode 5 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

思路:

动态规划

为了改进暴力法,我们首先观察如何避免在验证回文时进行不必要的重复计算。考虑

这个示例。如果我们已经知道
是回文,那么很明显,
一定是回文,因为它的左首字母和右尾字母是相同的。

我们给出

的定义如下:

因此,

基本示例如下:

这产生了一个直观的动态规划解法,我们首先初始化一字母和二字母的回文,然后找到所有三字母回文,并依此类推…

ab206c32929a4d020c9e92bdbfeaba7d.png

复杂度分析

  • 时间复杂度:O(n^2)O(n2),这里给出我们的运行时间复杂度为 O(n^2)O(n2) 。
  • 空间复杂度:O(n^2)O(n2),该方法使用 O(n^2)O(n2) 的空间来存储表。

具体写码的时候用一个变量(代码中的sub)来记录目前最长的子串长度,用一个list(代码中的max_len)来记录最长子串的坐标

另一个leetcode上速度比较快的算法有点类似滑动窗口法,维护一个最大长度为lenth的窗口,并使用python语法糖q == q[::-1]来判断是否是回文字符串,但是要注意的是维护窗口时要同时维护奇数和偶数两种窗口。

答案:

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        n = len(s)
        if n == 0:
            return ''
        if n == 1:
            return s
        res = [[0 for _ in range(n)] for _ in range(n)]
        sub = 1
        max_len = [0,0]
        for i in range(n):
            res[i][i] = 1
            if i != n-1 and s[i] == s[i+1]:
                res[i][i+1] = 1
                sub = 2
                max_len=[i,i+1]
        for i in range(n):
            for j in range(1,min(i,n-i)+1):
                if i-j>=0 and i+j<n and res[i-j+1][i+j-1] and s[i-j]==s[i+j]:
                    res[i-j][i+j] =1
                    #print 1+2*j
                    if sub<1+2*j:
                        sub = 1+2*j
                        max_len = [i-j,i+j]
                    #print sub,max_len
                if i-j>=0 and i+1+j<n and res[i-j+1][i+j] and s[i-j] == s[i+j+1]:
                    res[i-j][i+j+1] =1
                    if sub<2+2*j:
                        sub = 1+2*j
                        max_len = [i-j,i+j+1]
        #print sub,max_len
        return s[max_len[0]:(max_len[1]+1)]
class Solution(object):
 def longestPalindrome(self, s):
 """
        :type s: str
        :rtype: str
        """
 if len(s) == 1 or s == s[::-1]:
 return s
        start = 0
        length = 1
 for i in range(len(s)):
            p = s[i-length-1:i+1]
            q = s[i-length:i+1]
 if i-length-1 >= 0 and p == p[::-1]:
                start = i-length-1
                length += 2
 if i-length >=0 and q == q[::-1]:
                start = i - length
                length += 1
 return s[start:start+length]

[647] 回文子串

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

示例 1:

输入: "abc"

输出: 3

解释: 三个回文子串: "a", "b", "c".

示例 2:

输入: "aaa"

输出: 6

说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".

注意:

输入的字符串长度不会超过1000。

思路:

这道题的动态规划思路跟上一道题(第五题)完全一样,只不过在具体代码的时候,使用一个变量来记录回文子串的个数。

[516] 最长回文子序列

给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。

示例 1:

输入:

"bbbab"

输出:

4

一个可能的最长回文子序列为 "bbbb"。

示例 2:

输入:

"cbbd"

输出:

2

一个可能的最长回文子序列为 "bb"。

思路:

这道题跟上两道题的动态规划思路完全不一样,首先,这道题寻找的是最长回文子序列,子序列可以不相连。其次,这道题要返回的是最长回文子序列的长度,不关心子序列,所以构造动态规划数组时也稍有不同。具体来说:

引入

,表示第i个字符至第j个字符组成的子串中最长回文子序列的长度。

递推公式可以表示为:

1e55d60fd8c4b8a9710c5dd435828023.png

注意在具体代码的时候,循环应该是先判断间隔距离为1的所有字符对,然后依次增加。

答案:

class Solution(object):
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        if n<=1:
            return n
        if n==2:
            if s[0]==s[1]:
                return 2
            else:
                return 1
            
        resgrid = [[0 for _ in range(n)] for _ in range(n)]

        for i in range(n):
            resgrid[i][i]=1
        for gap in range(1,n):
            for i in range(n):
                if i+gap>=n:
                    break
                l = i
                h = i+gap
                if s[l]==s[h]:
                    resgrid[l][h] = resgrid[l+1][h-1]+2
                else:
                    resgrid[l][h]=max(resgrid[l+1][h],resgrid[l][h-1])
        return resgrid[0][n-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值