LCS算法

1、最长公共子序列(LCS)算法Java语言的简单实现:

    String lcs(String x, String y) {//输入序列x,y;返回最长公共子序列

        int[][] c = new int[x.length() + 1][y.length() + 1];//用来存放算法输出的结果值
        char[] cx = x.toCharArray();
        char[] cy = y.toCharArray();
        StringBuilder lcs = new StringBuilder();
        for (int i = 0; i <= cx.length; i++) {
            c[i][0] = 0;
        }
        for (int i = 0; i <= cy.length; i++) {
            c[0][i] = 0;
        }
        for (int i = 1; i <= x.length(); i++) {//算法实现
            for (int j = 1; j <= y.length(); j++) {
                if (cx[i-1] == cy[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];
                }
            }
        }

        Stack<Character> stack = new Stack<Character>();
        int i = x.length() - 1;
        int j = y.length() - 1;

        while ((i >= 0) && (j >= 0)) {
            if(cx[i] == cy[j]){//字符串从后开始遍历,如若相等,则存入栈中
                stack.push(cx[i]);
                i--;
                j--;
            } else {
                if (c[i+1][j] >= c[i][j+1]) {//如果字符串的字符不同,则在数组中找相同的字符,注意:数组的行列要比字符串中字符的个数大1,因此i和j要各加1
                    j--;
                } else {
                    i--;
                }
            }
        }

        while(!stack.isEmpty()){
            lcs.append(stack.pop());
        }
        return lcs.toString();
    }

    时间复杂度为O(mn),空间复杂度为O(mn)。

    算法思想(动态规划):

    (1)空序列是任意两个序列的公共子序列;

    (2)比较X[i],Y[j],若X[i]与Y[j]相同,则LCS(X(i), Y(j)) = LCS(X(i-1), Y(j-1)) + 1;

    (3)比较X[i],Y[j],若X[i]与Y[j]不同,则LCS(X(i), Y(j)) = max(LCS(X(i), Y(j-1)),LCS(X(i-1), Y(j)))。

    下面,就可以根据算法思想写出它的递归公式:

    (1)c[i][j] = 0    (i=0, j=0)

    (2)c[i][j] = c[i-1][j-1] + 1    (i>0, j>0, x[i] = y[j])

    (3)c[i][j] = max(c[i][j-1] ,c[i-1][j])    (i>0, j>0, x[i] != y[j])

    由此,可画出如下c[i][j]。

                        

    同样的,当要从c表内取出最长公共子序列时,可使用栈,从后向前遍历,根据递归公式,遍历出最长公共子序列,加入栈中,取出时正好是正向的最长公共子序列。

2、最长公共子串的Java实现

    public static String lcsubstring(String x, String y) {
        int n = 0;
        int max = 0;

        char[] a = x.toCharArray();
        char[] b = y.toCharArray();
        int[][] c = new int[a.length+1][b.length+1];

        for (int i = 0; i < a.length; i++) {
            c[i][0] = 0;
        }
        for (int j = 0; j < b.length; j++) {
            c[0][j] = 0;
        }
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < b.length; j++) {
                if (a[i] == b[j]) {
                    c[i+1][j+1] = c[i][j] +1;
                    if (max < c[i+1][j+1]) {
                        max = c[i+1][j+1];
                        n = i+1;
                    }
                } else {
                    c[i+1][j+1] = 0;
                }
            }
        }
        return x.substring(n-max, n);
    }

    时间复杂度为O(mn),空间复杂度为O(mn)。前提是使用动态规划(DP),如果想要暴力计算,会更消耗时间。它的动态规划要比最长公共子序列简单,理解了最长公共子序列,最长公共子串就很好理解了。

    公式:

    (1)c[i][j] = 0    (i>=0, j>=0, x[i+1] != y[j+1])

    (2)c[i][j] = c[i-1][j-1] + 1    (i>0, j>0, x[i] = y[j])

    最后,要取出最长公共子串,可以找一个值max标记当前最长的子串长度,一个值标记最长的子串结尾的位置。由这两个值就可以取出最长公共子串了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值