如何在指数时间内找到最长公共子序列?

时间:2012-01-25 21:21:04

标签: algorithm big-o sequence pseudocode exponential

我可以使用动态编程以正确的方式执行此操作,但我无法弄清楚如何在指数时间内完成此操作。

我正在寻找两个字符串之间最大的公共子序列。 注意:我的意思是子序列而不是子串,构成序列的符号不必是连续的。

6 个答案:

答案 0 :(得分:6)

只需使用递归调用替换动态编程代码中表中的查找。换句话说,只需实现LCS问题的递归表达式:

enter image description here

修改

在伪代码中(几乎是python,实际上):

def lcs(s1, s2):
 if len(s1)==0 or len(s2)==0: return 0
 if s1[0] == s2[0]: return 1 + lcs(s1[1:], s2[1:])
 return max(lcs(s1, s2[1:]), lcs(s1[1:], s2))

答案 1 :(得分:1)

假设您有两个长度为a的字符串bn。最长的公共子序列将是字符串a中最长的子序列,它也存在于字符串b中。

因此,我们可以遍历a中所有可能的子序列,并看到它位于b

对此的高级伪代码将是:

for i=n to 0
    for all length i subsequences s of a
        if s is a subsequence of b
            return s

答案 2 :(得分:1)

字符串A和字符串B.递归算法,也许它很幼稚,但很简单:

查看A的第一个字母。这将是一个共同序列或不同。在考虑'not'选项时,我们会剪掉第一个字母并递归调用。当考虑''在一个共同的序列'选项时,我们也将它修剪掉,我们也从B的开头到B.并包括在B中的相同字母。一些伪代码:

def common_subsequences(A,B, len_subsequence_so_far = 0):
    if len(A) == 0 or len(B) == 0:
        return
    first_of_A = A[0] // the first letter in A.
    A1 = A[1:] // A, but with the first letter removed
    common_subsequences(A1,B,len_subsequence_so_far) // the first recursive call
    if(the_first_letter_of_A_is_also_in_B):
        Bn = ... delete from the start of B up to, and including,
             ... the first letter which equals first_of_A
        common_subsequences(A1,Bn, 1+len_subsequence_so_far )

你可以从那开始,然后通过记住到目前为止找到的最长子序列进行优化,然后在当前函数无法击败时(即min(len(A), len(B))+len_subsequence_so_far小于到目前为止找到的最长长度时返回)。 / p>

答案 3 :(得分:0)

基本上如果你不使用动态编程范例 - 你会达到指数时间。这是因为,通过不存储您的部分值 - 您将多次重新计算部分值。

答案 4 :(得分:0)

为了达到指数时间,它足以生成两个阵列的所有子序列并将每个阵列相互比较。如果匹配两个相同的检查它们的长度是否大于当前最大值。伪代码将是:

Generate all subsequences of `array1` and `array2`.
for each subsequence of `array1` as s1
    for each subsequece of `array2` as s2
        if s1 == s2 //check char by char
            if len(s1) > currentMax
                currentMax = len(s1)
for i = 0; i < 2^2; i++;

绝对不是最佳。它甚至没有尝试过。然而问题是关于效率非常低的算法,所以我提供了一个。

答案 5 :(得分:-1)

int lcs(char[] x, int i, char[] y, int j) {
    if (i == 0 || j == 0) return 0;
    if (x[i - 1] == y[j - 1]) return lcs(x, i - 1, y, j - 1) + 1;
    return Math.max(lcs(x, i, y, j - 1), lcs(x, i - 1, y, j));
}

print(lcs(x, x.length, y, y.length);

以下是部分递归树:

                       lcs("ABCD", "AFDX")
                      /                   \
     lcs("ABC", "AFDX")                   lcs("ABCD", "AFD")
       /            \                      /               \
lcs("AB", "AFDX") lcs("AXY", "AFD")    lcs("ABC", "AFD") lcs("ABCD", "AF") 

最坏的情况是当LCS的长度为0时,这意味着没有共同的子序列。在这种情况下,将检查所有可能的子序列,并且有O(2^n)个子序列。