2.4.1题目描述
如果一个子序列从左向右和从右向左读都一样,则称之为回文。例如,序列ACGTGTCAAAATCG有很多回文子序列,比如ACGCA和AAAA。请给出一个算法,求出最长的回文子序列
2.4.2程序使用说明
Java 环境1.8.0_111
IDE:eclipse
直接运行PalindromeSequence.java文件,在控制台查看结果
2.4.3简要分析和设计
动态规划思想。对于任意字符串,如果头尾字符相同,那么字符串的最长子序列等于去掉首尾的字符串的最长子序列加上首尾;如果首尾字符不同,则最长子序列等于去掉头的字符串的最长子序列和去掉尾的字符串的最长子序列的较大者。加色字符串S,F(S,i,j)表示求字符串S[i...j]之间的最长会问子序列。则可以得到如下递归公式。
公式三
此处可以使用两种方式进行计算,使用循环的方式,或者使用递归的方式。此处介绍使用循环的方式。创建一个矩阵A,在程序中及一个二维数组,矩阵A(i,j)记录F(S,i,j)的值,使用循环的方式,线计算i,j之间间隔0个字符串的情景。令A(i,i)=0,i=1...n,假设i,j之间间隔k个字符。则A(i,j)=A(i-1,j-1)+2,S[i]==s[j],当A(i,j)=max(A(i+1,j),A(i,j-1)),s[i]!=s[j],最后计算的到A[0,n]的值,即为所求的长度。n为S的长度。然后在使用回溯法,求得S中被选择的字符串。
伪代码:
输入:字符串s,矩阵m[1...s.length,1...s.length],需要比较的字符串的开始字符下标i和结束字符下标j
输出:字符串s的最长回文子序列
PalindromeSequence(m[1,..s.length,1,..s.length],s,i,j)
For i <- 0 to s.length
m[i][i]= 0;
For k=1 to s.length-1
For i <- 0 to s.length-1-k
j=i+k
If s[i]==s[j]
m[i][j]=max(m[i+1][j-1]+1,m[i+1][j-1],m[i][j-1])
Else
m[i][j]=max(m[i+1][j],m[i][j-1])
Return m[0][s.length-1]
时间复杂度:O(n^2)
2.4.4测试用例
测试用例一:ACGTGTCAAAATCG
结果:长度:8 回文序列:CTAAAATC
测试用例二 :JHTTPPPXNSDWGJ
结果:长度:5 回文序列:JPPPJ
测试用例三:HPPWMMMTYQPV
结果:长度:5 回文序列:PMMMP
2.4.5源代码
package two.four;
/**
* 求一个字符串的会问子序列
* @author ym
*
*/
public class PalindromeSequence {
/**
* 求一个字符的最长回文子序列
*
* @param str
* @return
*/
public int palindrome(Stringstr,int[][]counts){
int len =str.length();
int[][] res = new int[len][len];
for(int i=0;i<len;i++){
res[i][i]=1;
counts[i][i]=1;
}
for(int i=1;i<len;i++){
for(int j=0;j<len-i;j++){
int k =j+i;
if(str.charAt(j)==str.charAt(k)){
if(k-j==1){
res[j][k]=2;
}
else{
res[j][k]=res[j+1][k-1]+2;
}
counts[j][k]=1;
}
else if(res[j+1][k]>res[j][k-1]){
res[j][k]=res[j+1][k];
counts[j][k]=-1;
}
else{
res[j][k]=res[j][k-1];
counts[j][k]=-2;
}
}
}
return res[0][len-1];
}
/**
* 回溯返回会问字符串结果
*
* @param str
* @param counts
* @return
*/
public String traceback(Stringstr,int[][]counts){
//回文字串前半部分记录结果
String sRes = "";
//记录回文字串后半部分结果
String eRes="";
int sIndex = 0;
int eIndex=counts.length-1;
while(sIndex<=eIndex){
if(str.charAt(sIndex)==str.charAt(eIndex)){
if(sIndex!=eIndex){
sRes+=str.charAt(sIndex);
}
eRes=str.charAt(eIndex)+eRes;
sIndex++;
eIndex--;
}
else if(counts[sIndex][eIndex]==-1){
sIndex++;
}
else{
eIndex--;
}
}
return sRes+eRes;
}
public static void main(String[]args) {
PalindromeSequence ps =new PalindromeSequence();
//测试用例1
String str1="ACGTGTCAAAATCG";
int[][] counts = new int[str1.length()][str1.length()];
System.out.println(ps.palindrome(str1,counts));
System.out.println(ps.traceback(str1,counts));
//测试用例2
String str2 ="JHTTPPPXNSDWGJ";
int[][] counts1 = new int[str2.length()][str2.length()];
System.out.println(ps.palindrome(str2,counts1));
System.out.println(ps.traceback(str2,counts1));
//测试用例三
String str3 = "HPPWMMMTYQPV";
int[][] counts2 = new int[str3.length()][str3.length()];
System.out.println(ps.palindrome(str3,counts2));
System.out.println(ps.traceback(str3,counts2));
}
}