赞
踩
给定两个字符串,寻找这两个字符串之间的最长公共自子序列(给出全部)
一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
一个给定序列的子序列是在该序列中删去若干元素后得到的序列。确切的说,若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},X的子序列是指存在一个严格的递增下标序列{i1,i2,…,ik}使得对所有的j=1,2,…,k有zj=xij。例如:序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B},相应的递增下标序列为{2,3,5,7}。
若X={A,B,C,B,D,A,B},Y={B,D,C, A,B,A};
可以看出,最长公共子序列并不唯一!!!
1.最长公共子序列的结构
最长公共子序列问题具有最优子结构性质。
设序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列为Z={z1,z2,…,zk},则:
(1)若xm=yn,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共子序列。
(2)若xm!=yn,且zk!=xm,则Z是Xm-1和Y的最长公共子序列。
(3)若xm!=yn,且zk!=yn,则Z是X和Yn-1的最长公共子序列。
其中,Xm-1={x1,x2,…,xm-1};Yn-1={y1,y2,…,yn-1};Zk-1={z1,z2,…,zk-1}
.
2. 子问题的递归结构
递归计算求得最长公共子序列:
(1)当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得到X和Y的最长公共子序列。
(2)当xm!=yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列以及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长的即为X和Y的最长公共子序列。
建立子问题最优值的递归关系:
3. 计算最优值
public static int lcsLength(char []x,char []y,int [][]b){ //c[i][j]存储Xi和Yj的最长公共子序列的长度; //b[i][j]记录c[i][j]的值是由哪一个子问题的解得到的。 //c[m][n],问题的最优值,即X和Y的最长公共子序列的长度。 int m=x.length-1; int n=y.length-1; int [][]c=new int [m+1][n+1]; for(int i=1;i<=m;i++){ c[i][0]=0; } for(int i=1;i<=n;i++){ c[0][i]=0; } for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ if(x[i]==y[j]){ c[i][j]=c[i-1][j-1]+1; b[i][j]=1; }else if(c[i-1][j]>=c[i][j-1]){ c[i][j]=c[i-1][j]; b[i][j]=2; }else{ c[i][j]=c[i][j-1]; b[i][j]=3; } } } return c[m][n]; }
4.构造最长公共子序列
由算法lcsLength计算得到的数组b可用于快速构造序列X和Y的最长公共子序列。
(1)当b[i][j]==1时,表示Xi和Yj的最长公共子序列是由Xi-1和Yj-1的最长公共子序列在尾部加上xi所得到的子序列;
(2)当b[i][j]==2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同;
(3)当b[i][j]==3时,表示Xi和Yi的最长公共子序列与Xi和Yj-1的最长公共子序列相同。
算法lcs实现根据b的内容打印Xi和Yj的最长公共子序列。
public static void lcs(int i,int j,char []x,int [][]b){
if(i==0||j==0)
return;
if(b[i][j]==1){
lcs(i-1,j-1,x,b);
System.out.print(x[i]);
}else if(b[i][j]==2){
lcs(i-1,j,x,b);
}else{
lcs(i,j-1,x,b);
}
}
package com.jiyongfei.lcs2; import java.util.Scanner; import java.util.TreeSet; /** * * @Description 最长公共子序列 * @author jiyongfei Email:2384074837@qq.com * @version * @date 2020年6月22日下午9:39:07 * */ public class LongestLcs { public StringBuffer X; public StringBuffer Y; public static int m; public static int n; public static int[][] b; public int[][] c; public int len; public String[] Log; public final int MAX = 100; public char[] lcs; public int CurLen; public static void main(String[] args) { LongestLcs lcs = new LongestLcs(); lcs.search(); } public void search() { while (true) { System.out.println("\n" + "请选择功能:"); System.out.println("\n" + "1.寻找最长公共子序列"); System.out.println("\n" + "2.结束."); Scanner in = new Scanner(System.in); int choose = in.nextInt(); switch (choose) { case 1: System.out.println("请输入序列X:"); X = new StringBuffer(in.next()); System.out.println("请输入序列Y:"); Y = new StringBuffer(in.next()); lcs_length(); System.out.println("两序列的最长公共子序列为:"); StoreLCS(m, n, len); PrintLCS(); X.setLength(0); Y.setLength(0); break; case 2: in.close(); System.exit(0); break; default: in.close(); System.exit(-1); } } } /** * * @Description 计算最优值 * c[i][j]存储Xi和Yj的最长公共子序列的长度 * b[i][j]记录c[i][j]的值是由哪一个子问题的解得到的 * len=c[m][n],问题的最优值,即XY的最长公共子序列的长度 * @author jiyongfei * @date 2020年6月23日上午7:51:09 */ public void lcs_length() { m = X.length(); n = Y.length(); c = new int[m + 1][n + 1]; b = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { c[i][0] = 0; } for (int j = 0; j <= n; j++) { c[0][j] = 0; } for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (X.charAt(i - 1) == Y.charAt(j - 1)) { c[i][j] = c[i - 1][j - 1] + 1; b[i][j] = 0; } else if (c[i - 1][j] > c[i][j - 1]) { c[i][j] = c[i - 1][j]; b[i][j] = 1; } else if (c[i - 1][j] == c[i][j - 1]) { c[i][j] = c[i - 1][j]; b[i][j] = 2; } else { c[i][j] = c[i][j - 1]; b[i][j] = 3; } } } lcs = new char[m + 1]; len = c[m][n]; Log = new String[MAX]; CurLen = 0; } /** * * @Description 根据b的内容,存储Xi和Yi的最长公共子序列 * @author jiyongfei * @date 2020年6月23日上午8:09:01 * @param m * @param n * @param Len */ public void StoreLCS(int m, int n, int Len) { if (m == 0 || n == 0) { Log[CurLen] = new String(lcs); CurLen++; } else { if (b[m][n] == 0) { lcs[Len] = X.charAt(m - 1); Len--; StoreLCS(m - 1, n - 1, Len); } else if (b[m][n] == 1) { StoreLCS(m - 1, n, Len); } else if (b[m][n] == 2) { StoreLCS(m, n - 1, Len); StoreLCS(m - 1, n, Len); } else { StoreLCS(m, n - 1, Len); } } } /** * * @Description 算法PrintLCS打印最长公共子序列 * @author jiyongfei * @date 2020年6月23日上午8:09:51 */ public void PrintLCS() { TreeSet<String> tr = new TreeSet<String>();// 树集合定义 for (int i = 0; i < CurLen; i++) { tr.add(Log[i]); } String[] s2 = new String[tr.size()]; for (int i = 0; i < s2.length; i++) { s2[i] = tr.pollFirst(); // 返回并删除最低元素 System.out.println(s2[i]); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。