【写在前面】:最近在复习期末考试,所以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).