思考题15.2-最长回文子序列

【写在前面】:最近在复习期末考试,所以python专题有一段时间没有更新,等期末考试完之后继续更新python专题。明天就要考算法了,想着今晚写一下博客就当是复习一遍了,有什么写的不妥当的地方欢迎大佬指正。

【题目】:(最长回文子序列)回文(palindrome)是正序与逆序相同的非空字符串。例如,所有长度为1的字符串、civic、racerar、aibohphobia(害怕回文之意)都是回文。设计高效算法,求给定输入字符串的最长回文子序列。例如,给定输入character,算法应该返回carac。算法的运行时间是怎样的?

解:

1、分析问题:题目让我们设计一个高效算法,求给定输入字符串的最长回文子序列,这道题可以对比最长子数组问题。

2、算法设计思想描述:设X=<x1,x2,...xn>是输入字符串序列,Z=<z1,z2,...zm>是X的最长回文子序列(LPS),X(i,j)是指以xi开始以xj结束的子序列。由题意得Z应该满足以下情况:

1)若n=1,则m=1,且z1=x1.

2)若n=2,x1=xn,则m=2,z1=x1=xn=zm。

3)若n=2,x1!=xn,则m=1,z1=x1or xn。

4)若n>2,x1=xn,则m>2,z1=x1=xn=zm,Z(2,m-1)是序列X(2,n-1)的LPS

5)若n>2,x1!=xn,则若z1!=x1,那么Z是序列X(2,n)的LPS。

6)若n>2,x1!=xn,则若zm!=xn,那么Z是序列X(1,n-1)的LPS。

令P[i,j]为X(i,j)对应的LPS的长度,那么对于P[i,j]应该满足以下递归式:

1)当i=j时,p[i,j]=1;

2)当j=i+1,xi==xj,p[i,j]=2;

3)当j=i+1,xi!=xj,p[i,j]=1;

4)当j>i+1,xi==xj,p[i,j]=p[i+1,j-1]+2;

5)当j>i+1,xi!=xj,p[i,j]=max(p[i+1,j],p[i,j-1]).

所以我们就可以开始填二维数组p了。

3、伪代码:

LONGEST-PALINDROME(X)
    n = X.length
    let b[1..n, 1..n] and p[0..n, 0..n] be new tables
    for i = 1 to n - 1
        p[i, i] = 1
        j = i + 1
        if x[i] == x[j]
            p[i, j] = 2
            b[i, j] = "↙"
        else p[i, j] = 1
            b[i, j] = "↓"
    p[n, n] = 1
    for i = n - 2 downto 1
        for j = i + 2 to n
            if x[i] == x[j]
                p[i, j] = p[i + 1, j - 1] + 2
                b[i, j] = "↙"
            else if p[i + 1, j] ≥ p[i, j - 1]
                p[i, j] = p[i + 1, j]
                b[i, j] = "↓"
            else p[i, j] = p[i, j - 1]
                b[i, j] = "←"
    return p and b

代码说明:这里先填对角线的p,填p是完全按照我们关于p的递推式来填的。如果xi==xj,就说明这两个在子序列Z中,把它们放到子序列Z的头和尾部,所以长度+2。如果xi!=xj,那么LPS就是(xi+1,xj)和(xi,xj-1)的最长LPS。第一个for循环是填i==j和j=i+1的这三种情况的,后面就是对于的j>i+1的那几种情况,来进行填表。

 上面那个是得到LPS长度的代码,下面这个是输出具体的LPS的代码,因为我们在计算LPS长度的时候用到了数组b,这个数组b就是存储LPS的具体值的,如果是↙,那么代表xi和xj就在LPS中,一个在头一个在尾,中间加上剩余子序列的LPS,如果是↓或者←,那么就说明这个LPS中xi和xj只有一个,具体找哪个LPS子序列,可以从上面的代码中倒推出来。

GENERATE-LPS(b, X, i, j, S)
    if i > j
        return S
    else if i == j
        return S || x[i]
    else if b[i, j] == "↙"
        return x[i] || GENERATE-LPS(b, X, i + 1, j - 1, S) || x[i]
    else if b[i, j] == "↓"
        return GENERATE-LPS(b, X, i + 1, j, S)
    else return GENERATE-LPS(b, X, i, j - 1, S)

这个S就是序列,||在这里是连接符。如果是↙,那就把xi和中间i+1~j-1和xj连接起来,构成更长的LPS。如果不是的话就继续递归寻,最后返回一个子序列,这个子序列S就是我们要求的LPS。

4、算法时间复杂度分析:由计算LPS的长度的代码来看,这个算法的时间复杂度为O(n^2).

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值