我在这里使用了一个简单的例子
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
或者是递归函数,具有memoization和动态编程,迭代数组并填充值等等。
我知道有时递归是坏的,因为你可以用堆(或堆栈?)耗尽内存(尾递归?),但这是否会影响O表示法?
递归memoized算法是否具有与迭代版本相同的O符号/速度?
答案 0 :(得分:1)
通常,在考虑算法的复杂性时,我们会分别考虑空间和时间复杂度。
两个类似的算法,一个递归,一个转换为非递归,通常具有相同的时间复杂度,但空间复杂度不同。
在您的示例中,两个阶乘函数都是O(n)时间复杂度,但递归版本是O(n)空间复杂度,而O(1)则是迭代版本。
这种差异并不普遍。 Memoization占用空间,有时它占用的空间与递归版本使用的堆栈空间相当甚至更大。
答案 1 :(得分:0)
根据您用于存储备忘值的复杂程度,这两者将具有相同的复杂性顺序。例如,在Python中使用dict
(具有(分摊)O(1)
插入/更新/删除时间),使用memoization将具有相同的顺序(O(n)
),用于计算阶乘基本的迭代解决方案。
然而,正如人们可以谈论时间复杂性一样,人们也可以谈论空间复杂性。这里,迭代解决方案使用O(1)
内存,而memoized解决方案使用O(n)
内存。
答案 2 :(得分:0)
如果你在谈论渐近时间复杂性,当然这与使用相同算法的原因相同。 我猜你真正关心的是性能。对于C语言,递归可能会更加昂贵。
答案 3 :(得分:0)
您是否真的使用记忆结果? 除了订单是相同的(两个等效比例),对于单次运行的阶乘,记忆是没用的 - 你将通过一系列参数,并且它们都不会重复 - 你永远不会使用你保存的记忆的价值观,意味着你会浪费空间和时间存储它们,而不是在任何其他地方获得任何加速。
然而......一旦你有了你的记忆字典,那么后续的阶乘调用将小于O(n),并且将取决于历史。 I.E.如果计算阶乘(10),那么10和0之间的阶乘值可用于即时查找 - O(1)。如果你计算阶乘(15),它会得到15 * 14 * 13 * 12 * 11 *阶乘(10),它只是查找,总共6次(而不是15次)。
但是,我猜你也可以为迭代版本创建一个查找字典。记忆也无济于事 - 在这种情况下,factorial(10)只会将结果存储为10,而不是所有结果都存储为0,因为这是所有参数列表都会看到的。但是,该函数可以直接将这些中间值存储到memoization dict中。