LCS算法的两种JAVA实现方式
2015-06-14 12:39
525 查看
http://blog.csdn.net/dylgsy/article/details/8235778
http://blog.csdn.net/v_july_v/article/details/6695482
给定字符串A,B
Solution I:
1.构造数组 c i j 描述A串的前i位和B串的前J位的LCS长度
2.构造数组 trace i j 描述max相应位置得到的长度是由哪一步得出的
c的构造方法根据下列规则
trace的构造如下图所示
END和START表示该处是直接得到的结果,没有前置步骤。
END表示LCS=0,START表示LCS=1
其余的根据箭头方向来看就比较好理解了。
获得结果时从上往下遍历即可,总的时间复杂度O(mn)+O(m+n)
代码如下
Solution II:
构造矩阵L(p,m)
算法实现方式不复杂,原理并不是很明了,这里把过程详细描述一下,希望可以得到一些讨论。
首先假设A串长度不超过B串。
构造基于A串长度的方阵L(i,k)表示A[1..i]中长度为k的子串在B中最小位置(这里认为字符串的位置是最末尾字符的位置),如果不存在这样的子串,则长度为无穷(MAX)。
显然,LCS={k|L(A.length,k)!=MAX}max。
过程也是从下至上递推的。
首先初始化L(1,i),注意L(i,k)=k时,L(i,k+1),L(i,k+2)....均为k,因为相同长度的子串,位置最小的一定是从头开始的那一个。
然后循环,遍历并生成L,规则如下:
i>k时,显然,L(i,k)=MAX
如果L(i-1,k-1)存在,则
从L(i-1,k-1)+1开始遍历到B串结尾,遍历的位置记为j,若B[j]=A[i],则:
比较L(i-1,k)(如果存在)和J的大小,较小的一个即为所求的L(i,k)
这里因为上一步所求的结果中,L(i-1.k-1)实际上可以看做L(i,k)的一部分,因为如果前者(长度为k-1的LCS)存在的话,在L(i-1.k-1)所得的位置往后遍历,遇到与A[i]相等的字符,一定可以与前者组成长度为k的LCS。
L(i,k)=k时,L(i,k+1),L(i,k+2)....均为k,原因同上。
对于一个k,遍历i一遍后,所有L(i,k)均不存在,则k-1,即最后一次所得的k,即为我们要的LCS长度。
B[L(1,m-p+1)]B[L(2,m-p+2)]…B[L(k,i)]即为LCS。
代码如下:
http://blog.csdn.net/v_july_v/article/details/6695482
给定字符串A,B
Solution I:
1.构造数组 c i j 描述A串的前i位和B串的前J位的LCS长度
2.构造数组 trace i j 描述max相应位置得到的长度是由哪一步得出的
c的构造方法根据下列规则
trace的构造如下图所示
END和START表示该处是直接得到的结果,没有前置步骤。
END表示LCS=0,START表示LCS=1
其余的根据箭头方向来看就比较好理解了。
获得结果时从上往下遍历即可,总的时间复杂度O(mn)+O(m+n)
代码如下
//枚举
enum DIRECTION{ <span style="white-space:pre"> </span>LEFT,UP,UPLEFT,START,END <span style="white-space:pre"> </span>}
//核心算法
...
for(int i=0;i<ch1.length;i++) for(int j=0;j<ch2.length;j++){ if(ch1[i]!=ch2[j]){ if(i>0&&j>0){ if(c[i-1][j]>c[i][j-1]){ trace[i][j]=DIRECTION.LEFT; c[i][j]=c[i-1][j]; } else{ trace[i][j]=DIRECTION.UP; c[i][j]=c[i][j-1]; } }else{ if(i>0){ trace[i][j]=DIRECTION.LEFT; c[i][j]=c[i-1][j]; }else if(j>0){ trace[i][j]=DIRECTION.UP; c[i][j]=c[i][j-1]; }else{ trace[i][j]=DIRECTION.END; c[i][j]=0; } } }else{ if(i==0||j==0){ trace[i][j]=DIRECTION.START; c[i][j]=1; } else{ trace[i][j]=DIRECTION.UPLEFT; c[i][j]+=c[i-1][j-1]+1; } } } //calculate StringBuilder sb=new StringBuilder(""); int i=ch1.length-1,j=ch2.length-1; end: for(;i>=0&&j>=0;) switch(trace[i][j]){ case UP:j--;break; case LEFT:i--;break; case UPLEFT:sb.append(ch1[i]);j--;i--;break; case START:sb.append(ch1[i]);break end; case END:break end; } //输出(sb.reverse().toString()); //输出(c[ch1.length-1][ch2.length-1]);
Solution II:
构造矩阵L(p,m)
算法实现方式不复杂,原理并不是很明了,这里把过程详细描述一下,希望可以得到一些讨论。
首先假设A串长度不超过B串。
构造基于A串长度的方阵L(i,k)表示A[1..i]中长度为k的子串在B中最小位置(这里认为字符串的位置是最末尾字符的位置),如果不存在这样的子串,则长度为无穷(MAX)。
显然,LCS={k|L(A.length,k)!=MAX}max。
过程也是从下至上递推的。
首先初始化L(1,i),注意L(i,k)=k时,L(i,k+1),L(i,k+2)....均为k,因为相同长度的子串,位置最小的一定是从头开始的那一个。
然后循环,遍历并生成L,规则如下:
i>k时,显然,L(i,k)=MAX
如果L(i-1,k-1)存在,则
从L(i-1,k-1)+1开始遍历到B串结尾,遍历的位置记为j,若B[j]=A[i],则:
比较L(i-1,k)(如果存在)和J的大小,较小的一个即为所求的L(i,k)
这里因为上一步所求的结果中,L(i-1.k-1)实际上可以看做L(i,k)的一部分,因为如果前者(长度为k-1的LCS)存在的话,在L(i-1.k-1)所得的位置往后遍历,遇到与A[i]相等的字符,一定可以与前者组成长度为k的LCS。
L(i,k)=k时,L(i,k+1),L(i,k+2)....均为k,原因同上。
对于一个k,遍历i一遍后,所有L(i,k)均不存在,则k-1,即最后一次所得的k,即为我们要的LCS长度。
B[L(1,m-p+1)]B[L(2,m-p+2)]…B[L(k,i)]即为LCS。
代码如下:
int result=0; //Li(k) int[][] L=new int[char1.length+1][char1.length+1]; //init L[k][i] k=1 for(int i=1;i<=char1.length;i++){ L[1][i]=1+str2.indexOf(String.valueOf(char1[i-1])); if(L[1][i]==1){ for(int j=i+1;j<=char1.length;j++) L[1][j]=1; break; } } int nullCount=0; for(int k=2;k<=char1.length;k++){ nullCount=0; for(int i=1;i<=char1.length;i++){ if(i<k){ L[k][i]=MAX; nullCount++; continue; } int min=MAX; if(L[k-1][i-1]!=MAX){ if(L[k][i-1]!=MAX) min=L[k][i-1]; for(int j=L[k-1][i-1]+1;j<=char2.length;j++) if(char2[j-1]==char1[i-1]){ min=j<min?j:min; break; } } L[k][i]=min; if(L[k][i]==k){ for(int j=i+1;j<=char1.length;j++) L[k][j]=k; break; } if(L[k][i]==MAX) nullCount++; } if(nullCount==char1.length){ result=k-1; break; } } result=result==0?char1.length:result; StringBuilder sb=new StringBuilder(); int i=char1.length,k=result; while(k>0&&i>0) sb.append(char2[L[k--][i--]-1]); sb.reverse();
相关文章推荐
- java String对象是“引用”传递的
- Java基础之I/O详解(一)File篇
- Java之RMI(远程方法调用)
- Java转义符\\|
- java 如何避免“!=null”式的判空语句?
- java 关键字null
- Java并发编程-04-线程局部变量
- Java中的嵌套类、内部类、静态内部类
- [7] MQTT,mosquitto,Eclipse Paho---MQTT消息格式之CONNACK消息分析
- 《Java从入门到精通》第八章学习笔记
- java 线程池的原理以及使用
- protobuf 编码实现解析(java)
- java并发编程第四章 线程执行器(4)
- java笔记11 模板设计模式
- Java I/O : Java中的进制详解
- java 框架基础知识(1)----反射-->Spring IoC
- Java I/O : Java中的进制详解
- java的学习 持续更新
- SpringMVC简明教程(一)——搭建
- 总结Java equals()和hashCode()的联系