[英]Space and time complexity of recursive implementation of summation function
谁能建议以下代码的空间和时间复杂度? 我知道时间复杂度应该是 O(n) 因为 function 被调用 n 次,空间复杂度至少是 O(n) (因为堆栈空间),但是将 a[1:] 传递给 function 会导致空间复杂度增加? 我认为 a[1:] 会在省略第一个元素的同时创建一个新的副本,对吗?
def sum(a):
if len(a) == 1:
return a[0]
return a[0] + sum(a[1:])
时间复杂度类似于 theta(n^2) ,因为每次执行 a[i:] 时,基本上都会将列表从 i 复制到末尾,因此您必须遍历它。 至于空间复杂度,应用程序堆栈将包含您将调用的所有列表,首先是一个包含 n 个元素的列表,然后是 n-1,依此类推,直到 1,您将开始清空堆栈。 所以你最终也会得到一个 theta(n^2) 复杂度。
作为一个递归的 function,如果没有应用尾调用优化,考虑到它在 memory 堆栈上的执行,在这种情况下肯定会有至少O(n)
的空间复杂度。 但是让我们进一步分析一下:
时间复杂度
我们知道 sum 是递归的,它的停止条件是输入数组为单长度时。 所以我们知道Sum
在最坏的情况下至少会被调用O(n)
次,考虑到一个大小为n
的输入数组。 考虑一下它的递归,即循环。
然而,在 function 内部,我们有一个切片操作。 切片操作l[a:b]
为O(ba)
,因此此操作在第一次运行时的复杂度为O(n-1)
,在第二次运行时复杂度为 O( O(n-2)
,依此类推。 我们最初认为,它将执行整个数组的副本。 这个 function 的整体时间复杂度应该是O(n^2)
因为它在大小为n
的数组中为每个项目创建一个切片。
空间复杂度
现在讨论 memory 中的空间。
len(a) == 1
这里我们有一份来自 len(a) 的返回值的副本。
return a[0]
&
return a[0] + sum(a[1:])
在上面的两行中,我们将有一个值的另一个副本,它将存储到 function 的返回地址中。 该切片还具有O(n)
空间复杂度。
看到这一点,并考虑到编译器没有应用重大优化优化,例如减少,我们说这个 function 的空间复杂度为O(n)
,因为它将为每个输入生成恒定数量的副本并且将在大小为n
的数组中执行切片操作。
由于我们一开始说过递归就像一个循环,考虑到没有尾调用优化,整个 function 在最坏的情况下将执行n
次。 该程序将增加函数的 memory 堆栈,直到它达到停止条件,直到它最终可以从调用堆栈中“弹出”返回值。 因此,总空间复杂度也是O(n*log n)
(因为每次执行输入数组都更小)。
附言:
根据这个,我还认为len(a)
具有O(1)
时间复杂度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.