最长回文子串

  给定一个字符串 s s s,找到 s s s中最长的回文子串。例:‘bababd’的最长的回文子串为’babab’。记字符串 s s s长度为 n n n

暴力算法

def is_palinedrome(string):
    for s in range(len(string) // 2):
        if string[s] != string[len(string) - s - 1]:
            return False
    else:
        return True

def longest_palindrome(string):
    max_length = 0
    target_string, current_string = '', ''
    for index, s1 in enumerate(string):
        current_string = ''
        for s2 in string[index:]:
            current_string += s2
            if is_palinedrome(current_string):
                max_length = max(max_length, current_length)
                target_string = current_string if max_length == len(current_string) else target_string
    return target_string

  寻找需要两层循环,判断需要一层循环,故时间复杂度为 O ( n 3 ) O(n^3) O(n3);变量个数为常数个,故空间复杂度为 O ( 1 ) O(1) O(1)

暴力算法优化:动态规划

  状态: p [ j j ] [ i i ] p[jj][ii] p[jj][ii] 表示 s [ j j : i i + 1 ] s[jj:ii+1] s[jj:ii+1]是否为回文子串。
  状态转移方程: p [ j j ] [ i i ] = ( s [ j j ] = = s [ i i ]    a n d    p [ j j + 1 ] [ i i − 1 ] ) p[jj][ii]=(s[jj]==s[ii]\ \ and\ \ p[jj+1][ii-1]) p[jj][ii]=(s[jj]==s[ii]  and  p[jj+1][ii1])。即:子串为回文子串的条件为最外层两侧字符相同且内层为回文子串。
  边界条件: j j − i i ≤ 2 jj-ii\le 2 jjii2。即:当最内层子串长度为2或3且两侧字符相同时为回文子串。

def longest_palindrome(string):
    size = len(string)
    if size <= 1:
        return string

    max_length = 0
    begin, end = 0, 0
    p = [[False for _ in range(size)] for _ in range(size)]
    for index in range(size):
        p[index][index] = True

    for ii in range(size):
        for jj in range(ii):
            if string[ii] == string[jj]:
                if ii - jj <= 2:
                    p[jj][ii] = True
                else:
                    p[jj][ii] = p[jj + 1][ii - 1]
            else:
                p[jj][ii] = False
            if p[jj][ii] is True:
                if max_length < ii - jj + 1:
                    max_length = ii - jj + 1
                    begin, end = jj, ii
                # break
                # max_length = max(ii - jj + 1, max_length)
                # begin, end = jj, ii
    return string[begin:end + 1]

  循环的层数为两层,故时间复杂度为 O ( n 2 ) O(n^2) O(n2);由于需要用数组存储动态规划结果,故空间复杂度为 O ( n 2 ) O(n^2) O(n2)
  为什么不能在注释处跳出循环:当长回文子串包含短回文子串时,若跳出循环可能会导致短回文子串没有被遍历到,即:动态规划结果保存不全。进一步导致遍历长回文子串时内层为False,使长回文子串判定错误。例:‘abababa’。
  为什么只能在max_length改变时改变起点与终点:当长回文子串包含短回文子串时,改变起点与终点会使输出不全。

中心扩展

  回文串一定是对称的,所以可以每次循环选择一个中心,进行左右扩展,判断左右字符是否相等即可。需要注意的是,当回文串长度为奇数时,中心为一个字符;否则为两个字符。故需要进行两次循环。

def longest_palindrome(string):
    size = len(string)
    if size <= 1:
        return string
    max_length, target_string = 0, ''
    for ii in range(1, size - 1):
        current_string = string[ii]
        for jj in range(1, size):
            if ii < jj or ii + jj == size:
                break
            elif string[ii - jj] == string[ii + jj]:
                current_string = string[ii - jj] + current_string + string[ii + jj]
            else:
                break
        max_length = max(max_length, current_length)
        target_string = current_string if max_length == len(current_string) else target_string

    for ii in range(size - 1):
        if string[ii] != string[ii + 1]:
            continue
        current_string = string[ii] * 2
        for jj in range(1, size):
            if ii < jj or ii + jj + 1 == size:
                break
            elif string[ii - jj] == string[ii + jj + 1]:
                current_string = string[ii - jj] + current_string + string[ii + jj + 1]
            else:
                break
        max_length = max(max_length, current_length)
        target_string = current_string if max_length == len(current_string) else target_string
    return target_string

  两次循环的层数均为两层,故时间复杂度为 O ( n 2 ) O(n^2) O(n2);变量个数为常数个,故空间复杂度为 O ( 1 ) O(1) O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值