文本相似度计算之--- 编辑距离 && 最长公共子串
2014-09-02 14:19
295 查看
问题引入:在自然语言处理领域里,求文本相似度是最基本的问题,对于这个问题,可以分为大的两类,一种是基于字符串层次的相似度计算,一种是基于语义的相似度计算。我会循序渐进的讲给大家。
本文我们先来看最简单的两种基于字符串层面的相似度度量算法。
1. 最长公共子串
对于最长公共子串,不难想象,就是要求两个字符串中出现的共同字符部分,并且这些字符必须是连续的,比如,aaabcdeff和bcdffab,那么他们最长的公共子串即是bcd,长度为3,其实问题很简单,大家可以这么想,如果两个字符串的公共子串存在,那么可以有如下的推导:s1, s2为两个字符串,cnt为子串长度的计数数组,则:
if s1[i] == s2[j] , cnt[j]=cnt[j-1]+1;
else cnt[j]=0;
此处我们设置maxlen标记最大长度,若有cnt[j]>maxlen,则maxlen=cnt[j],然后记录位置j,以便可以输出最长公共子串。
下面附上代码:
public class Test{
public void findLCS(String s1,String s2){
int len1 = s1.length();
int len2 = s2.length();
char[] cs1 = s1.toCharArray();
char[] cs2 = s2.toCharArray();
int[] cnt = new int[100];
int maxlen = 0;
int pos = 0;
for(int i=0;i<len1;++i){
for(int j=len2;j>0;--j){//这里逆向遍历是为了防止覆盖cnt数组之前记录的结果,想不明白的话请在纸上模拟一下
if(cs1[i]==cs2[j-1]){
cnt[j]=cnt[j-1]+1;
if(cnt[j]>maxlen){
maxlen=cnt[j];
pos=j;
}
}else{
cnt[j]=0;
}
}
}
System.out.println(maxlen);
for(int i=0;i<maxlen;++i){
System.out.print(cs2[pos-maxlen+i]);//输出最长公共子串
}
}
public static void main(String[] args){
String s1="abcdefg";
String s2="aaabcfff";
Test test = new Test();
test.findLCS(s1, s2);
}
}
2. 编辑距离
对于编辑距离,就是说对于两个字符串s1和s2,我们要计算出从s1转换成s2所用的最小步数,转换操作只能是替换一个字符,插入一个字符,删除一个字符。
我们用edit(i,j)表示s1的长度为i的子串到s2的长度为j的子串的编辑距离,那么不难推导出:
if i==0 && j==0,edit(i,j)=0 --- (1)
if i==0 && j>0,edit(i,j)=j 因为s1此时的子串长度为0,从长度为0的串变到s2长度为j的串,当然要j歩了,对吧 --- (2)
if i>0 && j==0,edit(i,j)=i 同上理由 --- (3)
if i>0 && j>0,edit(i,j)=min{edit(i-1,j)+1,edit(i,j-1)+1,edit(i-1,j-1)+flag},其中若s1i != s2j,则flag=1,否则flag=0,这个不难理解吧?若不理解可以留言 --- (4)
附上代码,注意初始化时,edit(i,0)=i,edit(0,j)=j,对应于上述(2)(3)条:
public class EditDistance {
int[][] edit;
public EditDistance(){
}
public int getEditDistance(String s1,String s2){
int l1=s1.length();
int l2=s2.length();
int f;
char[] st1,st2;
edit = new int[l1+1][l2+1];
for
4000
(int i = 0;i<=l1;++i){
edit[i][0]=i;
}
for(int i = 0;i<=l2;++i){
edit[0][i]=i;
}
for(int i=0;i<l1;++i){
for(int j=0;j<l2;++j){
st1 = s1.toCharArray();
st2 = s2.toCharArray();
if(st1[i]==st2[j])f=0;
else f=1;
edit[i+1][j+1]=Math.min(edit[i][j+1]+1, edit[i+1][j]+1);
edit[i+1][j+1]=Math.min(edit[i+1][j+1], edit[i][j]+f);
}
}
return edit[l1][l2];
}
public static void main(String[] args){
EditDistance ed = new EditDistance();
int result = ed.getEditDistance("ababab","bababa");
System.out.println(result);
}
}
本文我们先来看最简单的两种基于字符串层面的相似度度量算法。
1. 最长公共子串
对于最长公共子串,不难想象,就是要求两个字符串中出现的共同字符部分,并且这些字符必须是连续的,比如,aaabcdeff和bcdffab,那么他们最长的公共子串即是bcd,长度为3,其实问题很简单,大家可以这么想,如果两个字符串的公共子串存在,那么可以有如下的推导:s1, s2为两个字符串,cnt为子串长度的计数数组,则:
if s1[i] == s2[j] , cnt[j]=cnt[j-1]+1;
else cnt[j]=0;
此处我们设置maxlen标记最大长度,若有cnt[j]>maxlen,则maxlen=cnt[j],然后记录位置j,以便可以输出最长公共子串。
下面附上代码:
public class Test{
public void findLCS(String s1,String s2){
int len1 = s1.length();
int len2 = s2.length();
char[] cs1 = s1.toCharArray();
char[] cs2 = s2.toCharArray();
int[] cnt = new int[100];
int maxlen = 0;
int pos = 0;
for(int i=0;i<len1;++i){
for(int j=len2;j>0;--j){//这里逆向遍历是为了防止覆盖cnt数组之前记录的结果,想不明白的话请在纸上模拟一下
if(cs1[i]==cs2[j-1]){
cnt[j]=cnt[j-1]+1;
if(cnt[j]>maxlen){
maxlen=cnt[j];
pos=j;
}
}else{
cnt[j]=0;
}
}
}
System.out.println(maxlen);
for(int i=0;i<maxlen;++i){
System.out.print(cs2[pos-maxlen+i]);//输出最长公共子串
}
}
public static void main(String[] args){
String s1="abcdefg";
String s2="aaabcfff";
Test test = new Test();
test.findLCS(s1, s2);
}
}
2. 编辑距离
对于编辑距离,就是说对于两个字符串s1和s2,我们要计算出从s1转换成s2所用的最小步数,转换操作只能是替换一个字符,插入一个字符,删除一个字符。
我们用edit(i,j)表示s1的长度为i的子串到s2的长度为j的子串的编辑距离,那么不难推导出:
if i==0 && j==0,edit(i,j)=0 --- (1)
if i==0 && j>0,edit(i,j)=j 因为s1此时的子串长度为0,从长度为0的串变到s2长度为j的串,当然要j歩了,对吧 --- (2)
if i>0 && j==0,edit(i,j)=i 同上理由 --- (3)
if i>0 && j>0,edit(i,j)=min{edit(i-1,j)+1,edit(i,j-1)+1,edit(i-1,j-1)+flag},其中若s1i != s2j,则flag=1,否则flag=0,这个不难理解吧?若不理解可以留言 --- (4)
附上代码,注意初始化时,edit(i,0)=i,edit(0,j)=j,对应于上述(2)(3)条:
public class EditDistance {
int[][] edit;
public EditDistance(){
}
public int getEditDistance(String s1,String s2){
int l1=s1.length();
int l2=s2.length();
int f;
char[] st1,st2;
edit = new int[l1+1][l2+1];
for
4000
(int i = 0;i<=l1;++i){
edit[i][0]=i;
}
for(int i = 0;i<=l2;++i){
edit[0][i]=i;
}
for(int i=0;i<l1;++i){
for(int j=0;j<l2;++j){
st1 = s1.toCharArray();
st2 = s2.toCharArray();
if(st1[i]==st2[j])f=0;
else f=1;
edit[i+1][j+1]=Math.min(edit[i][j+1]+1, edit[i+1][j]+1);
edit[i+1][j+1]=Math.min(edit[i+1][j+1], edit[i][j]+f);
}
}
return edit[l1][l2];
}
public static void main(String[] args){
EditDistance ed = new EditDistance();
int result = ed.getEditDistance("ababab","bababa");
System.out.println(result);
}
}
相关文章推荐
- 基于编辑距离和最长公共子串计算字符串相似度
- 【转】最大和子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 数组字符串那些经典算法:最大子序列和,最长递增子序列,最长公共子串,最长公共子序列,字符串编辑距离,最长不重复子串,最长回文子串 (转)
- 求两个字符串的最长公共子串,最长公共子序列,编辑距离
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 找工作知识储备(2)---数组字符串那些经典算法:最大子序列和,最长递增子序列,最长公共子串,最长公共子序列,字符串编辑距离,最长不重复子串,最长回文子串
- 最长公共子串、最长公共子序列、字符串编辑距离
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 数组字符串那些经典算法:最大子序列和,最长递增子序列,最长公共子串,最长公共子序列,字符串编辑距离,最长不重复子串,最长回文子串
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 转:最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 【转载】最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 编辑距离,最长公共子序列,最长公共子串,最长递增子序列
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- java文本相似度计算(Levenshtein Distance算法(中文翻译:编辑距离算法))----代码和详解
- 编辑距离,最长公共子序列,最长公共子串,最长递增子序列
- 编辑距离,最长公共子序列,最长公共子串,最长递增子序列