最常见的子序列(LCS)强力算法

时间:2014-11-18 01:33:11

标签: algorithm brute-force lcs

我想创建一个强力算法来找到2个字符串之间最大的公共子序列,但我很难以算法的形式列举所有可能性。

我不想要一个动态的编程答案,因为奇怪的是我设法解决了这个问题(你会认为蛮力方法会更容易)。请使用伪代码,因为我更喜欢理解它并自己编写。

3 个答案:

答案 0 :(得分:4)

它与DP减去记忆部分几乎相同。

LCS(s1, s2, i, j):
    if(i == -1 || j == -1)
        return 0
    if(s1[i] == s2[j])
        return 1 + LCS(s1, s2, i-1, j-1)
    return max(LCS(s1, s2, i-1, j), LCS(s1, s2, i, j-1))

我们的想法是,如果我们有两个字符串s1和s2,其中s1在i处结束,而s2在j处结束,则LCS为:

  • 如果任一字符串为空,则最长的公共子序列为0.
  • 如果字符串1的最后一个字符(索引i)与字符串2(索引j)中的最后一个字符(索引i)相同,那么答案是1加上s1的LCS和s2结束于i-1和j-1 , 分别。因为很明显这两个指数对LCS有贡献,所以最好对它们进行计数。
  • 如果最后一个字符不匹配,那么我们会尝试删除其中一个字符。因此,我们尝试在s1(结束于i-1)和s2(结束于j)和s1(结束于i)和s2(结束于j-1)之间找到LCS,然后取两者的最大值。

时间复杂度显然是指数级的。

答案 1 :(得分:4)

我喜欢@ turingcomplete的答案,但它并不是真正的蛮力,因为它实际上并没有列举所有候选解决方案。例如,如果字符串是" ABCDE"和#34; XBCDY",递归方法不会测试" ABC"与" XBC"因为测试" A"与" X"会失败的。尽管如此,你是否想要将其视为一个独特的候选人,这是一种意见问题。事实上,你可以争辩说" ABC"与" ABCDY"也是一个有效的候选人,并且由于长度差异而立即失败。您可以在下面的代码中添加单独的LALB,以完全枚举这些候选人。

for L = min(A.length, B.length) to 1
{
    for iA = 0 to A.length - L - 1
    {
        for iB = 0 to B.length - L - 1
        {
            for i = 0 to L - 1
            {
                if(A[iA] != B[iB])
                {
                    match failed;
                }
            }
            if match didn't fail, then
            A[iA..iA+L] and B[iB..iB+L] are a maximal common substring
        }
     }
}
no common substring

答案 2 :(得分:0)

这是一个Java方法,用于存储/列出ArrayList中给定字符串的所有子序列。

  • 找到给定2个字符串的所有子序列
  • 找到它们之间的共同点
  • 其中最长的一个是答案

递归解决方案:

    void subSeq(String s, ArrayList<String> h)
    {
         int n = h.size();
         for(int i=0;i<n;i++)
             h.add(h.get(i) + s.charAt(0));

         if(s.length()>1)
             subSeq(s.substring(1,s.length()),h);
    }
  • 首次调用subSeq()时,ArrayList应该包含一个空字符串。

  • 我们已经知道每个字符都可以
         1)出现
             或
         2)不会出现在任何子序列中。

  • 因此,我们保持ArrayList中的所有字符串不变(上面的情况2)。

  • 此外,我们添加(到ArrayList)字符串,这些字符串是 与ArrayList中已经存在的字符串的串联

    字符串的第一个字符(上述情况1)。

  • 这涵盖(解决了)我们问题的上述两种情况。

  • 征服第一个字符后,我们递归调用该方法
    再次使用上述字符串的子字符串(不包含第一个字符)
    ,该子字符串将被发送以获取其第一个字符 被征服了。

  • 这将一直持续到我们收到长度为1的字符串。

迭代解决方案:

ArrayList<String> subSeq(String s)
    {
        ArrayList<String> h = new ArrayList<String>();
        h.add("");
        int n = s.length();
        int l;
        for(int i=0;i<n;i++)
        {
            l = h.size();
            for(int j=0;j<l;j++)
                h.add( h.get(j) + s.charAt(i));
        }
        return h;
    }