Algorithm 理解最长公共子序列算法的时间复杂度

Algorithm 理解最长公共子序列算法的时间复杂度,algorithm,recursion,lcs,subsequence,Algorithm,Recursion,Lcs,Subsequence,我不理解最长公共子序列算法的递归函数所具有的O(2^n)复杂性 通常,我可以将这个符号与算法的基本操作数(在本例中是比较)联系起来,但这一次在我看来没有意义 例如,有两个长度相同的字符串5。在最坏的情况下,递归函数计算251比较。而2^5甚至不接近该值 有人能解释这个函数的算法复杂性吗 def lcs(xstr, ystr): global nComp if not xstr or not ystr: return "" x, xs, y, ys = xs

我不理解最长公共子序列算法的递归函数所具有的
O(2^n)
复杂性

通常,我可以将这个符号与算法的基本操作数(在本例中是比较)联系起来,但这一次在我看来没有意义

例如,有两个长度相同的字符串
5
。在最坏的情况下,递归函数计算
251
比较。而
2^5
甚至不接近该值

有人能解释这个函数的算法复杂性吗

def lcs(xstr, ystr):
    global nComp
    if not xstr or not ystr:
        return ""
    x, xs, y, ys = xstr[0], xstr[1:], ystr[0], ystr[1:]
    nComp += 1
    #print("comparing",x,"with",y)
    if x == y:
        return x + lcs(xs, ys)
    else:
        return max(lcs(xstr, ys), lcs(xs, ystr), key=len)
O(2^n)
表示运行时间与足够大的
n
成比例。这并不意味着这个数字是坏的、高的、低的,或者任何特定于一个小的
n
,它也没有给出计算绝对运行时间的方法

为了得到隐含的意思,你应该考虑N=1000, 2000, 3000,甚至100万,200万等的运行时间。


在您的示例中,假设对于n=5,算法的最大迭代次数为251次,那么
O(n)
预测是,对于n=50,它将在
2^(50)/2^(5)的范围内*251
=
2^45*251
=
~8.8E15
迭代。

要正确理解它,请仔细查看图表,并在阅读图表时遵循自上而下的递归方法

Here, xstr = "ABCD"
      ystr = "BAEC"

                                    lcs("ABCD", "BAEC")       // Here x != y 
                                  /                     \  
                lcs("BCD", "BAEC")   <--  x==y   -->    lcs("ABCD", "AEC")  x==y
                          |                                        |
                          |                                        |
                  lcs("CD", "AEC")   <--  x!=y   -->     lcs("BCD", "EC")
                 /                \                     /                \
                /                  \                   /                  \
               /                    \                 /                    \
      lcs("D","AEC")                  lcs("CD", "EC")              lcs("BCD", "C")
    /                \              /               \              /        \       
lcs("", "AEC")        lcs("D","EC")                  lcs("CD", "C")        lcs("BCD","")
  |        \         /              \                       |             /       |
Return     lcs("", "EC")    lcs("D" ,"C")            lcs("D", "")   lcs("CD","")  Return
           /         \       /         \             /        \       /        \ 
        Return      lcs("","C")    lcs("D","") lcs("","")  Return  lcs("D","")  Return
                     /     \         /     \      /                 /      \
                  Return   lcs("","")       Return            lcs("", "")  Return
                                 |                                  |
                              Return                            Return
这里,xstr=“ABCD” ystr=“BAEC” lcs(“ABCD”,“BAEC”)//这里x!=Y / \ lcs(“BCD”、“BAEC”)lcs(“ABCD”、“AEC”)x==y | | | | 信用证(“CD”、“AEC”)信用证(“BCD”、“EC”) / \ / \ / \ / \ / \ / \ 信用证(“D”、“AEC”)信用证(“CD”、“EC”)信用证(“BCD”、“C”) / \ / \ / \ lcs(“,”AEC“)lcs(“D”,“EC”)lcs(“CD”,“C”)lcs(“BCD”,”) | \ / \ | / | 返回lcs(“,”EC“)lcs(“,”D“,”C“)lcs(“,”)lcs(“,”CD“,”)返回 / \ / \ / \ / \ 返回lcs(“,”C“)lcs(“,”)lcs(“,”)返回lcs(“,”)返回 / \ / \ / / \ 返回lcs(“,”)返回lcs(“,”)返回 | | 返回 注意:递归调用的正确表示方法通常是使用树方法,但我在这里使用图方法只是为了压缩树,这样人们就可以很容易地理解递归调用。当然,我也很容易代表


  • 因为,在上图中存在一些冗余对,如
    lcs(“CD”、“EC”)
    ,这是从
    lcs(“CD”、“AEC”)
    中的
    “AEC”
    中删除
    “A”
    ,以及从
    lcs(“BCD”、“EC”)中的
    “BCD”
    中删除
    “B”
    。因此,在执行时会多次调用这些对,这增加了程序的时间复杂性

  • 正如您很容易看到的,每对都会为其下一个级别生成两个结果,直到遇到任何空字符串或
    x==y
    。因此,如果字符串的长度为n,m(考虑到xstr的长度为
    n
    ,而ystr的长度为
    m
    ,我们正在考虑最坏的情况)。然后,我们将在订单的末尾显示数字结果:2n+m。(怎么做?想想)

因为,n+m是一个整数,比如说n。因此,算法的时间复杂度:O(2N),这对于N的较大值是无效的

因此,与递归方法相比,我们更喜欢动态规划方法。当n==m时,它可以将时间复杂度降低到:O(n.m)=>O(n2)

即使现在,如果您很难理解逻辑,我建议您为
xstr=“ABC”
ystr=“EF”
创建一个类似于
的树(不是我在这里显示的图形)。我希望你能理解


任何疑问,欢迎评论。

您可能希望包括您正在查看并试图理解的特定算法描述。大O复杂性决定了函数如何在非常大的值下增长,直至常数因子。一个算法可以是O(1),但仍然需要1亿次运算。或
O(n)
并对
n=1
执行50000次操作,对
n=2
执行10000次操作。这完全取决于它如何随着N的任意增大而增长。此外,5是一个非常小的
n
值。没有算法,就没什么可说的了。@CollinD但是有两个字符串,它们的大小甚至可能不同,n是什么?我将算法添加到帖子中。在这种情况下,n很可能是较长字符串的长度。好的,我明白了,但是有两个字符串,它们的大小甚至可能不同,什么是n?因为最长的公共子序列永远不会比较短的字符串长,所以它可能是较短字符串的长度。不是说它太重要了(2^n)并不意味着与2^n成正比。@Aganju它不是更长的长度吗