算法导论 — 思考题15-2 最长回文子序列

最长回文子序列)回文(palindrome)是正序与逆序相同的非空字符串。例如,所有长度为1的字符串、civic、racecar、aibohphobia都是回文。设计高效算法,求给定输入字符串的最长回文子序列。例如,给定输入character,算法应该返回carac。算法的运行时间是怎样的?
  
  
  假设有一个字符串S[1..n]=s1,s2,,snS[1..n] = {s_1, s_2, …, s_n}P[1..k]=p1,p2,,pkP[1..k] = {p_1, p_2, …, p_k}SS的任意最长回文子序列(Longest Palindrome Subsequence, LPS)。
  比较首字符s1s_1和尾字符sns_n,可以分以下3种情况:
  1) 如果s1=sns_1 = s_n,则有p1=s1p_1 = s_1pk=snp_k = s_n,并且P[2..k1]P[2..k-1]S[2..n1]S[2..n-1]的一个LPS;
  2) 如果s1sns_1 ≠ s_n,那么s1p1s_1 ≠ p_1意味着P[1..k]P[1..k]S[2..n]S[2..n]的一个LPS;
  3) 如果s1sns_1 ≠ s_n,那么snpks_n ≠ p_k意味着P[1..k]P[1..k]S[1..n1]S[1..n-1]的一个LPS。
  需要补充说明一下。根据上文第(1)点给出的结论,如果s1=sns_1 = s_n,只需要求解S[2..n1]S[2..n-1]的LPS,并将s1s_1sns_n分别加到S[2..n1]S[2..n-1]的LPS的头部和尾部,从而得到S[1..n]S[1..n]的一个回文子序列,我们假设这个回文子序列的长度为l1l_1。然而,严格来说,还需要求解S[1..n1]S[1..n-1]S[2..n]S[2..n]的LPS,它们也是S[1..n]S[1..n]的回文子序列,假设这两个LPS的长度分别为l2l_2l3l_3。我们需要比较l1l_1l2l_2l3l_3的大小,其中最大者对应的回文子序列才是S[1..n]S[1..n]的LPS。然而,上文第(1)点为何断言l1l_1一定是最大的?我们采用反证法来说明。
  假设l1<l2l_1 < l_2,并假设S[2..n1]S[2..n-1]的LPS的长度为l4l_4,有l1=l4+2l_1 = l_4 + 2。如果S[1..n1]S[1..n-1]的LPS不包含s1s_1,那么将s1s_1S[1..n1]S[1..n-1]中去掉,S[1..n1]S[1..n-1]的LPS实际上也是S[2..n1]S[2..n-1]的LPS,故l2=l4l_2 = l_4,于是有l1=l2+2>l2l_1 = l_2 + 2 > l_2。这与l1<l2l_1 < l_2矛盾。
  如果S[1..n1]S[1..n-1]的LPS包含s1s_1,那么S[1..n1]S[1..n-1]的LPS的尾字符一定等于s1s_1,将S[1..n1]S[1..n-1]的LPS的首尾字符去掉,得到的子序列一定是S[2..n1]S[2..n-1]的一个回文子序列(假设它的长度为l5l_5,有l2=l5+2l_2 = l_5 + 2),并且一定有l4l5l_4 ≥ l_5,故l1=l4+2l5+2=l2l_1 = l_4 + 2 ≥ l_5 + 2 = l_2,这也与l1<l2l_1 < l_2矛盾。故l1l2l_1 ≥ l_2是一定成立的。
  同理,l1l3l_1 ≥ l_3也是成立的。综上所述,上文结论(1)是对的。
  可以看到,LPS问题与最长公共子序列问题是很类似的,也具有最优子结构。
  • 如果s1=sns_1 = s_n,那么需要求解子问题S[2..n1]S[2..n-1]的LPS,并将s1s_1sns_n分别加到S[2..n1]S[2..n-1]的LPS的头部和尾部,从而得到S[1..n]S[1..n]的LPS
  • 如果s1sns_1 ≠ s_n,那么需要分别求解两个子问题S[2..n]S[2..n]S[1..n1]S[1..n-1]的LPS,二者中较长者即为S[1..n]S[1..n]的LPS。
  用c[i,j]c[i, j]表示子序列S[i,j]S[i, j]的LPS的长度,可以得到以下递归式:
        算法导论 — 思考题15-2 最长回文子序列
  我们可以自下而上的求解最长回文子序列问题。下面给出该算法的伪代码。
  算法导论 — 思考题15-2 最长回文子序列
  与LCS类似,LPS的时间复杂度为Θ(n2)Θ(n_2)。下图展示了对字符串character运行了LPS-LENGTH的结果。
  算法导论 — 思考题15-2 最长回文子序列
  本节相关的code链接。
  https://github.com/yangtzhou2012/Introduction_to_Algorithms_3rd/tree/master/Chapter15/Problems/Problem_15-2