动态规划:最长公共子序列和最长公共子串

孤街醉人 提交于 2019-11-30 06:13:56

一、最长公共子序列问题(LCS问题)

我们首先需要搞清楚以下两个概念:最长公共子序列 VS 最长公共子串:

找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续。

问题描述:

给定两个字符串,求解这两个字符串的最长公共子序列(Longest Common Sequence)。比如字符串1:BDCABA;字符串2:ABCBDAB,则这两个字符串的最长公共子序列长度为4,最长公共子序列是:BCBA

动态规划解法分析:

A=(A1,A2,…An)B={B1,B2,…Bm} 是两个序列,将 A 和 B的最长公共子序列记为LCS(A,B)

找出LCS(A,B)就是一个最优化问题。因为,我们需要找到A 和 B中最长的那个公共子序列。而要找A 和 B的LCS,首先考虑A的最后一个元素和B的最后一个元素。

  1. 如果 An=Bm,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(An-1,Bm-1)
  2. 如果An != Bm,产生了两个子问题:LCS(An-1,Bm) 和 LCS(An,Bm-1),因为序列A 和 序列B 的最后一个元素不相等,那说明最后一个元素不可能是最长公共子序列中的元素。求解上面两个子问题,得到的公共子序列谁最长,那谁就是 LCS(A,B)。用数学表示就是:LCS=max{LCS(An-1,Bm),LCS(An,Bm-1)}

我们要求c[i] [j],先判断str1的第i个元素str2的第j个元素是否相同即判断str[i - 1]str[j -1]是否相同,如果相同它就是c[i - 1] [j- 1] +1,相当于在两个字符串都去掉一个字符时的最长公共子串再加 1;否则最长公共子串取c[i] [j-1]或c[i-1] [j]

public class LCSequence {

    //求解str1 和 str2 的最长公共子序列
    public static int LCS(String str1, String str2) {
        int[][] c = new int[str1.length() + 1][str2.length() + 1];
        for (int row = 0; row <= str1.length(); row++)
            c[row][0] = 0;
        for (int column = 0; column <= str2.length(); column++)
            c[0][column] = 0;

        for (int i = 1; i <= str1.length(); i++)
            for (int j = 1; j <= str2.length(); j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1))
                    c[i][j] = c[i - 1][j - 1] + 1;
                else c[i][j] = c[i][j - 1] > c[i - 1][j] ? c[i][j - 1] : c[i - 1][j];
            }
        return c[str1.length()][str2.length()];
    }

    //test
    public static void main(String[] args) {
        String str1 = "BDCABA";
        String str2 = "ABCBDAB";
        int result = LCS(str1, str2);
        System.out.println(result);
    }
}

二、最长公共子串问题(LCS问题)

我们要求c[i] [j],先判断str1的第i个元素str2的第j个元素是否相同即判断str[i - 1]str[j -1]是否相同,如果相同它就是c[i - 1] [j- 1] +1,相当于在两个字符串都去掉一个字符时的最长公共子串再加 1;否则最长公共子串取0。

public class LongestSubstring {

    //求解str1 和 str2 的最长公共子串
    public static int findLongest(String str1, String str2) {
        int[][] c = new int[str1.length() + 1][str2.length() + 1];
        for (int row = 0; row <= str1.length(); row++)
            c[row][0] = 0;
        for (int column = 0; column <= str2.length(); column++)
            c[0][column] = 0;

        int res = 0;
        for (int i = 1; i <= str1.length(); i++)
            for (int j = 1; j <= str2.length(); j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)){
                    c[i][j] = c[i - 1][j - 1] + 1;
                    res = Math.max(res, c[i][j]);
                }
                else c[i][j] = 0;
            }
        return res;
    }

    //test
    public static void main(String[] args) {
        String str1 = "HelloWorld";
        String str2 = "loop";
        int result = LCS(str1, str2);
        System.out.println(result);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!