动态规划和中心扩散法等解决回文数问题(python实现)

问题

  该问题是力扣上一道中等难度的题目,但是方法却有多样,值得记录一下。题干如下:

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

  下面给出三种方法:暴力解法,中心扩散和动态规划。

解答

暴力解法

  首先想到的就是无脑的暴力解法,从左到右遍历,记初始的一个字符串长度为 1 ,当遍历找到一个回文子串时,字符串的长度加一,不断增加知道找不到该长度的回文子串。这个方法比较好想出来,但是由于遍历的原因,时间复杂度较高,运算的时间也就较高。

  判断是否为回文子串的方法是分两种情况:

  1. 字符串长度 n 为奇数,0 到 n − 1 2 \frac{n-1}{2} 2n1 n + 1 2 \frac{n+1}{2} 2n+1 到 n 的子串是倒置的关系,只需要判断一下即可验证是否为回文数串;

  2. 字符串长度 n 为偶数,将字符串分为等距两段,判断是否为倒置关系。

    其代码如下:

 def judge_Palindrome(s):
     if len(s) % 2 == 1:   # odd
         if s[0:int(len(s) / 2)] == s[:int(len(s) / 2):-1]:
             return True
         else:
             return False
     elif len(s) % 2 == 0:   # even
         if s[0:int(len(s) / 2)] == s[-1:-int(len(s) / 2) - 1:-1]:
             return True
         else:
             return False

  接下来的思路就同一开始说的一样,遍历即可:

if len(s) < 2:
    l = s
else:
    l = s[0]
    i = 2
    while i <= len(s):
        for start_node in range(0, len(s) - i + 1):
            if judge_Palindrome(s[start_node:start_node + i]):
                l_longest = i
                l = s[start_node:start_node + i]
                break
            else :
                continue
        i = i + 1

中心扩散

  同样是从左向右遍历,以每个元素为一个中心,左右扩散到可以满足的最长回文串结束。

def center_spread(s, size, left, right):
    i = left
    j = right
    
    while i >= 0 and j < size and s[i] == s[j]:
        i -= 1
        j += 1
    return s[i + 1:j], j - i - 1    

if len(s) < 2:
    l = s
else :
    max_len = 1
    l = s[0]
    
    for i in range(len(s)):
        l_odd, odd_len = center_spread(s, len(s), i, i)
        l_even, even_len = center_spread(s, len(s), i, i + 1)
        # find the current maximum length
        cur_max_l = l_odd if odd_len > even_len else l_even
        if len(cur_max_l) > max_len:
            max_len = len(cur_max_l)
            l = cur_max_l

动态规划

  关键有两点:

  1. 定义“状态”

    d p [ l ] [ r ] dp[l][r] dp[l][r]表示子串 s [ l , r ] s[l, r] s[l,r](包括区间左右端点)是否构成回文串,是一个二维布尔型数组。即如果子串 s [ l , r ] s[l, r] s[l,r] 是回文串,那么 d p [ l ] [ r ] = T r u e dp[l][r] = True dp[l][r]=True

  2. 找到“状态转移方程”

dp[l, r] = (s[l] == s[r] and (r - l <= 2 or dp[l + 1, r - 1]))

  当 s [ l , r ] s[l,r] s[l,r]是回文字串时,毋庸置疑, s [ l + 1 , r − 1 ] s[l+1,r-1] s[l+1,r1]也是回文字串,唯一注意的是,当 s [ l + 1 , r − 1 ] s[l+1,r-1] s[l+1,r1]只有1个或者没有元素的时候,是无法用dp判断的,但是此时一定是回文字串,因为 s [ l ] = s [ r ] s[l] = s[r] s[l]=s[r]

下面给出代码:

size = len(s)
if size < 2:
    res = s
else :
    dp = [[False for _ in range(size)] for _ in range(size)]
    longest_l = 1
    res = s[0]
    for r in range(1, size):
        for l in range(size):
            if s[l] == s[r] and (r - l <= 2 or dp[l + 1][r - 1]):
                dp[l][r] = True
                cur_len = r - l + 1
                if cur_len > longest_l:
                    longest_l = cur_len
                    res = s[l:r + 1]

− − − − − − − − − − − − − − − − ----------------
该文章首发于 zyairelu.cn
欢迎来到我的网站进行评论及研讨
个人邮箱[email protected]
− − − − − − − − − − − − − − − − ----------------

猜你喜欢

转载自blog.csdn.net/weixin_42731543/article/details/102767373