来源于:http://www.java3z.com/cwbwebhome/article/article18/report92.html?id=4867
回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。现在的任务是,求出将给定字符串变成回文词所需要插入的最少字符数
。比如:“Ab3bd”插入2个字符后可以变成回文词“dAb3bAd”或“Adb3bdA”,但是插入少于2个的字符无法变成回文词。
[输入]:
第一行:字符串的长度N(3 <= N <= 5000)
第二行:需变成回文词的字符串
[输出]:
将给定字符串变成回文词所需要插入的最少字符数
[样例]:
![](/qrcode.jpg)
Sample Input
5
Ab3bd
Sample Output
2
分析:
S和S' (注:S'是S的反串)的最长公共子串其实一定是回文的。这样我们就可以借助lcs来解决该题,即用s的长度减去lcs的值即可。
import java.io.BufferedReader; import java.io.InputStreamReader; public class Main { public static void main(String[] args) throws Exception{ BufferedReader in = new BufferedReader(new InputStreamReader (System.in)); int total = Integer.parseInt(in.readLine()); String string = in.readLine(); System.out.println(total-LCS(string,new StringBuffer(string).reverse().toString())); } //返回两个string的lcs的长度 public static int LCS(String str1,String str2){ short length1 = (short)str1.length(); short length2 = (short)str2.length(); short[][]result = new short [2][length2+1]; //滚动数组,节省空间 for(int i=1;i<=length1;i++){ for(int j=1;j<=length2;j++){ if(str1.charAt(i-1)==str2.charAt(j-1)) result[i%2][j] = (short)(result[(i-1)%2][j-1]+1); else result[i%2][j] = result[(i-1)%2][j]>result[i%2][j-1]?result[(i-1)%2][j]:result[i%2][j-1]; } } return result[length1%2][length2]; } }
由求lcs算法设计到具体实现源码:
来源于:http://blog.csdn.net/fightforyourdream/article/details/20015641 讲解的非常详细
LCS:又称 最长公共子序列。 其中子序列(subsequence)的概念不同于串的子串。它是一个不一定连续但按顺序取自字符串X中的字符序列。 例如:串"AAAG"就是串“CGATAATTGAGA”的一个子序列。
字符串的相似性问题可以通过求解两个串间的最长公共子序列(LCS)来得到。 当然如果使用穷举算法列出串的所有子序列,一共有2^n种,而每个子序列是否是另外一个串的子序列又需要O(m)的时间复杂度,因此这个穷举的方法时间复杂度是O(m*(2^n))指数级别,效率相当的可怕。我们采用动态规划算法来解决这个问题。
假如我们有两个字符串:X=[0,1,2....n] Y=[0,1,2...m]。我们定义L(i, j)为X[0...i]与Y[0...j]之间的最长公共子序列的长度。通过动态规划思想(复杂问题的最优解是子问题的最优解和子问题的重叠性质决定的)。我们考虑这样两种情况:
(1) 当X[i]=Y[j]时, L(i, j)=L(i-1, j-1)+1 。证明很简单。
(2) 当X[i]!=Y[j]时, 说明此事X[0...i]和Y[0...j]的最长公共子序列中绝对不可能同时含有X[i]和Y[j]。那么公共子序列可能以X[i]结尾,可能以Y[j]结尾,可以末尾都不含有X[i]或Y[j]。因此
L(i, j)= MAX{L(i-1 , j), L(i, j-1)}
package DP; public class LCS2 { /** 字符串X的字符数组 */ private char[] charArrayX = null; /** 字符串Y的字符数组 */ private char[] charArrayY = null; public LCS2(String sa, String sb) { charArrayX = new char[sa.length() + 1]; System.arraycopy(sa.toCharArray(), 0, charArrayX, 1, sa.length()); charArrayY = new char[sb.length() + 1]; System.arraycopy(sb.toCharArray(), 0, charArrayY, 1, sb.length()); } /** * 得到最长公共子序列的长度 */ public void getLCS() { int[][] length = new int[charArrayX.length + 1][charArrayY.length + 1]; for (int m = 1; m < charArrayX.length; m++) { for (int n = 1; n < charArrayY.length; n++) { if (charArrayX[m] == charArrayY[n]) { length[m][n] = length[m - 1][n - 1] + 1; } else length[m][n] = max(length[m - 1][n], length[m][n - 1]); // length[m][n] = max(length[m][n], length[m-1][n-1]); } } for (int m = 0; m < charArrayX.length; m++) { for (int n = 0; n < charArrayY.length; n++) { System.out.print(length[m][n] + " "); } System.out.println(); } // 打印最长公共子序列 String lcstr = ""; int x = charArrayX.length - 1; int y = charArrayY.length - 1; while (x >= 1 && y >= 1) { if (charArrayX[x] == charArrayY[y]) { lcstr = charArrayX[x] + lcstr; x--; y--; } else { if (length[x - 1][y] <= length[x][y - 1]) // 往值较大的路径走 y--; else x--; } } System.out.println("最长公共子序列为:" + lcstr + " [length=" + lcstr.length() + "]"); } /** * 取最大值 */ private int max(int m, int n) { return m > n ? m : n; } /** * 测试 */ public static void main(String[] args) { LCS2 lcs = new LCS2("GTTCCTAATA", "CGATAATTGAGA"); lcs.getLCS(); } }
问题拓展:设A,B,C是三个长为n的字符串,它们取自同一常数大小的字母表。设计一个找出三个串的最长公共子串的O(n^3)的时间算法。 (来自《Algorithm Design》(中文版:算法分析与设计) - Chapter9 - 文本处理 - 创新题C-9.18)
public class TriLCS{ char[] charA=null; char[] charB=null; char[] charC=null; public TriLCS(String sa,String sb,String sc){ charA=new char[sa.length()+1]; System.arraycopy(sa.toCharArray(),0,charA,1,sa.length()); charB=new char[sb.length()+1]; System.arraycopy(sb.toCharArray(),0,charB,1,sb.length()); charC=new char[sc.length()+1]; System.arraycopy(sc.toCharArray(),0,charC,1,sc.length()); } public void getTriLCS(){ int[][][] length=new int[charA.length][charB.length][charC.length]; for(int a=1;a<charA.length;a++) for(int b=1;b<charB.length;b++) for(int c=1;c<charC.length;c++){ if(charA[a]==charB[b]&&charA[a]==charC[c]){ length[a][b][c]=length[a-1][b-1][c-1]+1; } else if(charA[a]==charB[b]&&charA[a]!=charC[c]){ length[a][b][c]=max(length[a-1][b-1][c],length[a][b][c-1]); } else if(charA[a]==charC[c]&&charA[a]!=charB[b]){ length[a][b][c]=max(length[a-1][b][c-1],length[a][b-1][c]); } else if(charB[b]==charC[c]&&charA[a]!=charB[b]){ length[a][b][c]=max(length[a][b-1][c-1],length[a-1][b][c]); } else{ length[a][b][c]=max(length[a-1][b][c],length[a][b-1][c],length[a][b][c-1],length[a-1][b-1][c],length[a-1][b][c-1],length[a][b-1][c-1]); } } //打印最长公共子序列 String lcstr=""; int a=charA.length-1; int b=charB.length-1; int c=charC.length-1; while(a>=1&&b>=1&&c>=1){ if(charA[a]==charB[b]&&charA[a]==charC[c]){ lcstr=charA[a]+lcstr; a--; b--; c--; } else if(charA[a]==charB[b]&&charA[a]!=charC[c]){ if(length[a-1][b-1][c]<=length[a][b][c-1]) c--; else{ a--; b--; } } else if(charA[a]==charC[c]&&charA[a]!=charB[b]){ if(length[a-1][b][c-1]<=length[a][b-1][c]) b--; else{ a--; c--; } } else if(charB[b]==charC[c]&&charA[a]!=charB[b]){ if(length[a][b-1][c-1]<=length[a-1][b][c]) a--; else{ b--; c--; } } else{ int maxize=max(length[a-1][b][c],length[a][b-1][c],length[a][b][c-1],length[a-1][b-1][c],length[a-1][b][c-1],length[a][b-1][c-1]); if(maxize==length[a-1][b][c]) a--; if(maxize==length[a][b-1][c]) b--; if(maxize==length[a][b][c-1]) c--; if(maxize==length[a-1][b-1][c]){ a--; b--; } if(maxize==length[a-1][b][c-1]){ a--; c--; } if(maxize==length[a][b-1][c-1]){ b--; c--; } } } System.out.println("最长子串为:"+lcstr+"(length="+length[charA.length-1][charB.length-1][charC.length-1]+")"); } /** * 取最大值 */ private int max(int m,int n){ return m>n?m:n; } /** * 取最大值 */ private int max(int x,int y,int z,int k,int m,int n){ int maxizen=0; if(maxizen<x) maxizen=x; if(maxizen<y) maxizen=y; if(maxizen<z) maxizen=z; if(maxizen<k) maxizen=k; if(maxizen<m) maxizen=m; if(maxizen<n) maxizen=n; return maxizen; } public static void main(String[] args){ TriLCS tri=new TriLCS("aadsbbbcs","adsabcs","adbsbsdcs"); tri.getTriLCS(); } }