动态规划——最长公共子序列计算

来源:互联网 发布:mac本地音乐播放器 编辑:程序博客网 时间:2024/05/23 14:22

最长公共子序列计算步骤:

第一步:先计算最长公共子序列的长度。

第二步:根据长度,然后通过回溯求出最长公共子序列。

现有两个序列X={x1,x2,x3,...xi},Y={y1,y2,y3,....,yi},

一共有两种情况,一种是

x1 = = y1,则长度为lcs({x2,x3,x4....xi},{y2,y3,....,yi})+1

若不等,则递归计算取

lcs({x1,x3,x4....xi},{y2,y3,....,yi}) lcs({x2,x3,x4....xi},{y1,y2,y3,....,yi})之中较大的值作为公共子序列的长度。

递推方程为:(此图片来源于网络)

    

动态规划最重要最核心的就是求出递推方程,有了递推方程,我们可以非常容易的利用递归写出代码:

public class LCS {     String x = "122f35624";     char [] m = x.toCharArray();     String y = "2135ff4";    char [] n = y.toCharArray();    int [][] a = new int[x.length()][y.length()];//用来保存中间计算的状态    public static void main(String[] args) {       LCS lcs = new LCS();        lcs.init();        int result = lcs.solve(0,0);        System.out.println();        System.out.println(result);        lcs.resolvePath(result);    }    public void init(){        for (int i=0; i<x.length(); i++)            for (int j=0; j<y.length(); j++){                a[i][j] = -1;            }    }    public  int solve(int i,int j){//记忆化搜索        if (i==x.length()|| j==y.length())            return 0;        if (a[i][j] >=0)//此处为了提高效率,防止重复计算,当计算过时直接返回值,不再重复计算            return a[i][j];        if (m[i]==n[j]){            return a[i][j] = solve(i+1,j+1)+1;        }        else        return a[i][j] = Math.max(solve(i+1,j),solve(i,j+1));    }    /**     * 打印最长公共字串     * @param result     */    public void resolvePath(int result){        int x = 0;        int y = 0;        char [] path = new char[result];        int count = 0;        while (x <m.length && y <n.length) {            if (m[x] == n[y]) {                path[count++] = m[x];                x++;                y++;            }            else if (x<m.length-1&&a[x][y] == a[x+1][y]){                x++;            }else if (y<n.length-1 &&a[x][y] == a[x][y+1])                y++;        }        for (int i=0; i<path.length; i++)            System.out.print(path[i]);    }}

除了利用递归方法解决上述问题外,还可以采用递推法解决。将上述函数换成数组

设一个c[i,j]: 保存Xi与Yj的LCS的长度。(此图片来源于网络)

对应代码如下:

    /**     * 递推法计算最长公共子序列     * @return 最长公共子序列长度     */    public int lcs(){        for (int i=0; i<m.length; i++){//0行0列初始化为0            a[i][0] = 0;            a[0][i] = 0;        }        for (int i=1; i<=m.length; i++)            for (int j=1; j<=n.length; j++){                if (m[i-1] == n[j-1])                    a[i][j] = a[i-1][j-1] + 1;                else                    a[i][j] = Math.max(a[i][j-1],a[i-1][j]);            }        return a[m.length][n.length];    }
打印公共子序列函数与递归法相同。

程序运行结果如下:


1 0
原创粉丝点击