对于记忆递归和迭代,Big O表示法相同吗

Is the Big O notation the same for memoized recursion versus iteration?

本文关键字:表示 Big 迭代 于记忆 记忆 递归      更新时间:2023-10-16

我在这里使用了一个简单的例子

function factorial(n)
if n==1 return 1
else return n*factorial(n-1)
function factorial(n)
result = 1
for i = 1 to n
result *= n
return result

或者是递归的、具有记忆功能的函数,而不是动态编程,在动态编程中迭代数组并填充值等。

我知道有时候递归很糟糕,因为使用堆(或堆栈?)可能会耗尽内存(尾递归?),但这会影响O表示法吗?

递归记忆算法是否具有与迭代版本相同的O符号/速度?

通常在考虑算法的复杂性时,我们会分别考虑空间和时间复杂性。

两种类似的算法,一种是递归算法,另一种是转换为非递归算法,通常具有相同的时间复杂度,但在空间复杂度上不同。

在您的示例中,两个阶乘函数都是O(n)时间复杂度,但递归版本是O(n)空间复杂度,而迭代版本则是O(1)。

这种差异并不普遍。记忆化占用空间,有时它所占用的空间与递归版本使用的堆栈空间相当,甚至更大。

根据存储存储值的复杂程度,两者的复杂程度相同。例如,在Python中使用dict(其具有(摊销的)O(1)插入/更新/删除时间),使用记忆将具有与基本迭代解决方案相同的阶乘计算顺序(O(n))。

然而,正如我们可以谈论时间复杂性一样,我们也可以谈论空间复杂性。这里,迭代解决方案使用O(1)内存,而内存化解决方案则使用O(n)内存。

如果你在谈论渐近时间复杂性,当然这是因为你使用了相同的算法。我想你真正关心的是表现。对于类C语言,递归可能会更加昂贵。

您真的要使用存储的结果吗?除了顺序相同(两者的比例相等)这一事实之外,对于一次阶乘运算来说,记忆是无用的——你会遍历一系列参数,它们都不会重复——你永远不会使用保存的记忆值,这意味着你会浪费存储它们的空间和时间,而不会在其他地方获得任何加速。

然而。。。一旦你有了记忆字典,那么随后的阶乘调用将小于O(n),并且将取决于历史。也就是说,如果计算阶乘(10),那么在10和0之间的阶乘值可用于即时查找-O(1)。如果你计算阶乘(15),它会得到15*14*13*12*11*阶乘(10),它只是查找它,总共6乘(而不是15)。

不过,我想您也可以为迭代版本创建一个查找dict。记忆化并没有多大帮助——在这种情况下,factorial(10)只会存储10的结果,而不是所有的结果都降到0,因为这就是参数列表所能看到的。但是,函数可以将这些中间值直接存储到记忆dict中。