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));
}
}