最长回文子串

5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd”
输出:“bb”
示例 3:
输入:s = “a”
输出:“a”
示例 4:
输入:s = “ac”
输出:“a”

可以使用从中心往两边的找法,以每一个点为中心,依次往两边扩展;也可以使用动态规划。

1、中心往两边
重点是注意考虑中心是1一个数还是两个数!!

class Solution(object):
    def longestPalindrome(self, s):

        def palindrome(i, j):
            out = 0
            while i >= 0 and j <= len(s) - 1:
                if s[i] == s[j]:
                    i -= 1
                    j += 1
                    out += 2
                else:
                    break
            i += 1
            j -= 1
            return out, s[i:j+1] 

        if not s:
            return ""
        out = 0
        longest = 0
        for i in range(len(s)):
            out1, sub1 = palindrome(i, i+1)  # 从前往后移动
            out2, sub2 = palindrome(i-1, i+1)  # 从中间往两边
            out2 += 1
            out = max(out1, out2)
            if out > longest:
                longest = out
                if out == out2:
                    sub_str = sub2
                else:
                    sub_str = sub1
        return sub_str

动态规划
首先,dp[i][j]代表的是s[i:j+1]是否是回文子串。
状态转移方程:
dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]
为什么是这个方程,我们可以通过画表格看出,
举例: 对于abbba,我们想看s[0:5],那么其实取决于s[1:4],因为只有s[1:4]是回文子串,那么s[0:5]才是回文子串。

这道题与以往有点不同的是,遍历的顺序有所改变,因为我们需要先得到dp[i+1][j-1],所以我们的遍历顺序是先对j进行遍历,再对i进行遍历。相当于从上往下进行的。
在这里插入图片描述

class Solution(object):
    def longestPalindrome(self, s):
        # 动态规划
        dp = []
        for i in range(len(s)):
            dp.append([0]*len(s))
        
        longest = 0
        sub_str = s[0]
        for j in range(len(s)):
            for i in range(0, j):
                if s[i] == s[j]:
                    if i+1 >= j-1:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i+1][j-1]
                    if dp[i][j]:
                        if j - i > longest:
                            longest = j-i
                            sub_str = s[i:j+1]
        return sub_str

得到二维的表示之后自然要优化空间:需要注意的是,上一子串是回文串并不代表目前的子串是回文串,所以当s[i] != s[j]的时候,就必须手动将dp[i][j] = 0。

class Solution(object):
    def longestPalindrome(self, s):
        # 动态规划
        dp = [0]*len(s)

        longest = 0
        sub_str = s[0]
        for j in range(len(s)):
            for i in range(j+1):
                if i == j:
                    dp[i] = 1
                elif s[i] == s[j]:
                    if i+1 > j-1:
                        dp[i] = 1
                    else:
                        dp[i] = dp[i+1]
                    if dp[i]:
                        if j - i > longest:
                            longest = j-i
                            sub_str = s[i:j+1]
                else:
                    dp[i] = 0  # 上一波虽然可能是1,但是现在不是回文子串了,所以必然是0,切记修改~
        return sub_str

另外一种解法:
相当于长度递增,从1到… 然后从左到右遍历。这样就可以使得每个区间都可以得到遍历,并且依次扩大。

def solution(nums):
    n = len(nums)
    dp = []
    for i in range(n):
        dp.append([""]*n)
    for i in range(n):
        dp[i][i] = 1
    mini = n-1
    minj = n-1
    for length in range(1, n):
        for i in range(n):
            j = i + length
            if j >= n:
                break
            if nums[i] == nums[j]:
                if j == i + 1:
                    dp[i][j] = 1
                    if j - i > minj - mini:
                        mini, minj = i, j
                else:
                    if dp[i+1][j-1]:
                        dp[i][j] = 1
                        if j-i > minj - mini:
                            mini, minj = i, j
    return minj-mini+1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值