LCS-最长公共子序列
概念:A和B的公共子序列中长度最长的(包含元素最多的)叫做A和B的公共子序列。
1)最简单的方法还是暴力解决,循环找出A与B的所有子序列,然后进行比对找出最长子序列
2)动态规划,首先给出递推式
首先解释递推式,针对序列Am<a1,a2,a3,a4,a5…am>Bn<b1,b2,b3…bn>,他们的最长公共子序列是Ck<c1,c2,c3…ck>,即存在以下两种情况
1)am = bn时,即am = bn = ck, 即Ck-1是Am-1和Bn-1的最长公共子序列
2)am != bn时,此时Ck是Am-1和Bn或Am和Bn-1的最长公共子序列
根据以上两种情况,可以得出依据于长度的递推式。C[I,J]表示Ai和Bj的最长公共子序列的长度。即可写出上图所示递推式。
依据递推式可以列出长度表示表。
在后续递归找出最长公共子序列
js代码如下
// "1代表左上"
// "2代表上"
// "3代表左"
(function(){
let A = "ACCGGTCGAGATGCAG".split("");
let B = "GTCGTTCGGAATGCAT".split("");
let LCS = "";
A.unshift("");
B.unshift("")
var init = function(){
let c = [];
for(let i = 0; i < A.length; i++){
c[i] = [];
c[i].length = B.length;
for(let j = 0; j < B.length; j++){
if(i == 0){
c[i][j] = {lcs: 0,source: 0};
}
if(j == 0 ){
c[i][j] = {lcs: 0,source: 0};
}
}
}
return c;
}
// 构建表
// 根据递归公式
var build = function () {
let c = init();
for(let i = 1; i < A.length; i++){
for(let j = 1; j < B.length; j++){
if(A[i] == B[j]){
c[i][j] = {
lcs: c[i - 1][j - 1].lcs + 1,
source: 1
};
}else{
if(c[i - 1][j].lcs > c[i][j - 1].lcs){
c[i][j] = {
lcs: c[i - 1][j].lcs,
source: 2
}
}else{
c[i][j] = {
lcs: c[i][j - 1].lcs,
source: 3
}
}
}
}
}
return c;
}
var lcs = function (c, x, i, j) {
if(i == 0 || j == 0){
return
}
if(c[i][j].source == 1){
LCS = x[i] + LCS;
lcs(c, x, i - 1, j - 1);
}else if(c[i][j].source == 2){
lcs(c, x, i - 1, j);
}else{
lcs(c, x, i, j - 1);
}
}
lcs(build(), A, A.length - 1, B.length - 1);
console.log(LCS);
})()