python O(n log n)中算法的时间复杂度

时间:2018-06-28 10:37:46

标签: python time-complexity

给出一个列表,说“ x”的长度为n,那么以下算法的时间复杂度是多少?

def foo(x):
  n = len(x)
  if n <= 1:
     return 17
  return foo(x[:n//2]) + foo(x[n//2:])

答案是:

  

O(n log n)

但是我不知道为什么吗? 我很难弄清楚我们使用递归的最后一行,我知道每次它将列表的长度减少一半,所以它的O(log n),但是它在每次迭代中都添加了另一个递归,它也是O(log n) ),因此我虽然使用了O(log n log n),但不幸的是不是。

4 个答案:

答案 0 :(得分:2)

您可以正确地确定 O(登录n),但是您无法确定它是什么是达到基本情况所需的步骤数。由于每次将列表切成两半,因此每次调用foo时,您使用的列表的大小是您刚拥有的列表的一半。因此,需要O(log n)步才能达到基本情况。

下一个问题是:每个步骤要完成多少工作?第一步,将列表分成两半,这需要n个内存副本。在第二步中,将大小为n/2两个列表分成两半。完成的工作量保持不变!从一个步骤到下一个步骤,您要削减的每个列表的大小为一半(由于调用了foo(n//2)),但是您必须这样做的列表数量要加倍(因为您递归调用foo两次)。因此,对于每一步,您总是在做O(n)工作。

O(log n)个步骤*每个步骤中O(n)的工作量=总共O(n log n)个。

答案 1 :(得分:0)

这类似于合并排序。在这里,您花费 O(n)时间来切片数组 as seen here,然后对列表的两半进行操作。合并排序的时间复杂度为O(n log(n))。

如果您想派生合并排序,可以看看this

答案 2 :(得分:0)

此算法为列表O(n)中的每个元素返回一次,然后还实现了对分搜索O(log n),因此,它是O(n log n)

  

但是我不知道为什么吗?我很难弄清楚我们使用递归的最后一行,我知道每次它将列表的长度减少一半,所以它的O(log n),但是它在每次迭代中都添加了另一个递归,它也是O(log n) ),因此我虽然使用了O(log n log n),但不幸的是不是。

O(log n) + O(log n) = O(log n)

为此添加一两个打印语句将有很大帮助:

def foo(x):
    n = len(x)
    print(x)
    if n <= 1:
        print("return")    
        return 17
    return foo(x[:n//2]) + foo(x[n//2:])

>>> foo([1,2,3,4,5,6,7,8])
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4]
[1, 2]
[1]
Return
[2]
Return
[3, 4]
[3]
Return
[4]
Return
[5, 6, 7, 8]
[5, 6]
[5]
Return
[6]
Return
[7, 8]
[7]
Return
[8]
Return

很显然,这会为列表中的每个元素返回一次,这使其至少为O(n)。此外,要以两分搜索类型拆分列表,需要O(log n)

答案 3 :(得分:0)

def foo(x):
   n = len(x) # outer
   if n <= 1: # inner
     return 17 # inner
   return foo(x[:n//2]) + foo(x[n//2:]) #outer

我们可以将功能分为2部分。第一个外部部分可以用“ n = len(x)”和“ return foo(x [:n // 2])+ foo(x [n // 2:])”定义,其中“ x”是递归分为2个。因此,外部函数为log n。在第二部分中,内部部分由“ if n <= 1:\ return 17”组成,其中n用“ n <= 1”搜索。因此内部函数只是n。结果,内部x外部给出了“ n.log n”。