计算字符串的最长回文子序列

本文介绍了如何使用Java实现动态规划算法来寻找字符串的最长回文子序列。详细解析了动态规划的设计思路,包括递归公式,并提供了测试用例验证算法的正确性。代码中包含 palindrome() 方法用于计算最长回文子序列的长度,以及 traceback() 方法用于回溯得到具体的回文子序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2.4.1题目描述

如果一个子序列从左向右和从右向左读都一样,则称之为回文。例如,序列ACGTGTCAAAATCG有很多回文子序列,比如ACGCAAAAA。请给出一个算法,求出最长的回文子序列

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 

结果:长度:回文序列:CTAAAATC

测试用例二 JHTTPPPXNSDWGJ

结果:长度:回文序列:JPPPJ

测试用例三:HPPWMMMTYQPV

结果:长度:回文序列: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));

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值