最长公共子序列问题
2010-12-06 16:11
67 查看
这是自动判题系统的描述
描述:
一个给定序列的子序列是在该序列中删去若干元素后得到的序列。确切地说,若给定序列X=<x1, x2,…,
xm>,则另一序列Z=<z1, z2,…, zk>是X的子序列是指存在一个严格递增的下标序列 <i1, i2,…,
ik>,使得对于所有j=1,2,…,k有:
Xij =
Zj
如果一个序列S即是A的子序列又是B的子序列,则称S是A、B的公共子序列。
求A、B所有公共子序列中最长的序列的长度。
输入:
输入共两行,每行一个由字母和数字组成的字符串,代表序列A、B。A、B的长度不超过200个字符。
输出:
一个整数,表示最长各个子序列的长度。
格式:printf("%d/n");
输入样例:
programming
contest
输出样例:
2
代码:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc=new Scanner(System.in); String str1=sc.nextLine(); String str2 =sc.nextLine(); System.out.println(lcsLength(str1,str2)); } //关于此问题,需要递归公式,c[i][j]记录序列Xi和yj的最长 //公共子序列的长度,当i=0或j=0时,空序列是两个字符串的最长 //公共子序列,故此时c[i][j]=0 //当Xi=yi时,c[i][j]=c[i-1][j-1]+1; //else max{c[i][j-1],c[i-1][j]} public static int lcsLength(String str1,String str2) { int m=str1.length(); int n=str2.length(); 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(str1.charAt(i-1)==str2.charAt(j-1)) c[i][j]=c[i-1][j-1]+1; else if(c[i-1][j]>=c[i][j-1]) c[i][j]=c[i-1][j]; else c[i][j]=c[i][j-1]; } return c[m] ; } }
但是这个程序只能计算出最长公共子序列的长度,那要是还想要知道是什么序列该怎么办呢?
import java.util.Scanner; public class Main { static int b[][];//此数组用于计算最长公共子序列中每个字符时怎么样得到的 public static void main(String[] args) { Scanner sc=new Scanner(System.in); String str1=sc.nextLine(); String str2 =sc.nextLine(); b=new int[str1.length()+1][str2.length()+1]; System.out.println(lcsLength(str1,str2,b)); lcs(str1.length(),str2.length(),str1,b); } //关于此问题,需要递归公式,c[i][j]记录序列Xi和yj的最长 //公共子序列的长度,当i=0或j=0时,空序列是两个字符串的最长 //公共子序列,故此时c[i][j]=0 //当Xi=yi时,c[i][j]=c[i-1][j-1]+1; //else max{c[i][j-1],c[i-1][j]} public static int lcsLength(String str1,String str2,int [][]b) { int m=str1.length(); int n=str2.length(); 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(str1.charAt(i-1)==str2.charAt(j-1)) { 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] ; } //构造最长公共子序列 public static void lcs(int i,int j,String str,int b[][]) { if(i==0||j==0) return; if(b[i][j]==1) { lcs(i-1,j-1,str,b); System.out.print(str.charAt(i-1)); } else if(b[i][j]==2) lcs(i-1,j,str,b); else lcs(i,j-1,str,b); } }
这个算法可以解决刚才说的问题。
下面由我来进一步解释一下最长公共子序列问题的解法,当然,这不是我发明的,从书上学来的。
最长公共子序列问题具有最优子结构性质。
设序列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)else if(zk不等于xm),则Z是Xm-1和Y的最长公共子序列
(3)else if(zk不等于yn),则Z是X和Yn-1的最长公共子序列
由此德奥递推公式
公共子序列,故此时c[i][j]=0 i=0 or j=0
当Xi=yi时,c[i][j]=c[i-1][j-1]+1;
else max{c[i][j-1],c[i-1][j]}
用数组b[i][j]记录c[i][j]的值是由哪一个子问题的解得到的,在构造最长公共子序列时用到了。
在构造最长公共子序列时,首先从b[m]
开始,依其值在数组b中搜索,当b[i][j]=1,表示Xi和Yj的最长公共子序列是由Xi-1和Yj-1的最长公共子序列尾部加上xi得到的序列。当b[i][j]=2时,表示Xi和Yj的最长公共子序列是由Xi-1和Yj的最长公共子序列相同,当b[i][j]=3时,表示Xi和Yj的最长公共子序列是由Xi和Yj-1的最长公共子序列相同,由此可找出最长公共子序列的具体内容。
相关文章推荐
- 动易2006序列号破解算法公布
- 解决ie动态修改link样式,import css不刷新的问题
- VBS ArrayList Class vbs中的数组类
- css import与link的区别
- 大家看了就明白了css样式中类class与标识id选择符的区别小结
- C#实现打造气泡屏幕保护效果
- C 语言基础教程(我的C之旅开始了)[三]
- C 语言基础教程(我的C之旅开始了)[七]
- Flex include和import ActionScript代码
- PHP STRING 陷阱原理说明
- asp.net String.IsNullOrEmpty 方法
- JavaScript 组件之旅(二)编码实现和算法
- javascript String 对象
- setAttribute 与 class冲突解决
- mysql输出数据赋给js变量报unterminated string literal错误原因
- javascript String 的扩展方法集合
- C#中string与byte[]的转换帮助类-.NET教程,C#语言
- javascript下string.format函数补充
- C 语言基础教程(我的C之旅开始了)[六]
- String与string的区别(注意大小写)