【问题标题】:Converting a function with two recursive calls into an interative function将具有两个递归调用的函数转换为迭代函数
【发布时间】:2017-01-01 07:20:00
【问题描述】:

我有一个有两个递归调用的函数,我正在尝试将它转换为一个迭代函数。我已经弄清楚了我可以很容易地用一个电话在哪里做到这一点,但我不知道如何合并另一个电话。

功能:

def specialMultiplication(n):
    if n < 2:
        return 1
    return n * specialMultiplication(n-1) * specialMultiplication(n-2)

如果我只有其中一个,那真的很容易:

def specialMult(n, mult = 1):
    while n > 1: 
        (n, mult) = (n-1, n * mult) # Or n-2 for the second one
    return mult

我只是不知道如何添加第二个电话以获得总体正确的答案。谢谢!

【问题讨论】:

  • 您的算法的运行时间是指数级的。无论您是递归还是迭代地实现它,都只会将运行时间改变一个常数因子。
  • 谢谢@merlin2011。我现在看到了。只是想弄清楚如何将其转换为动态样式。
  • Blckknght 的答案是应该在线性时间内运行的 DP 解决方案。

标签: python python-3.x recursion


【解决方案1】:

如果您不介意稍微更改算法的结构,您可以以自下而上的方式计算值,从最小值开始。

def specialMultiplication(max_n):
    a = b = 1
    for n in range(1, max_n+1):
        a, b = b, a*b*n
    return b

【讨论】:

    【解决方案2】:

    使用辅助“待办事项列表”将递归转换为迭代函数:

    def specialMultiplication(n):
        to_process = []
        result = 1
        if n >= 2:
            to_process.append(n)
            while to_process:  # while list is not empty
                n = to_process.pop()
                result *= n
                if n >= 3:
                    to_process.append(n-1)
                    if n >= 4:
                       to_process.append(n-2)
        return result
    
    1. 创建工作清单 (to_process)
    2. 如果n &gt;= 2,将n添加到列表中
    3. to_process不为空时,从列表中弹出项目,乘以结果
    4. 如果n-1 &lt; 2,不要执行“左”操作(不要追加到工作列表)
    5. 如果n-2 &lt; 2,不要执行“正确”操作(不要追加到工作列表)

    这种方法的优点是消耗更少的堆栈。我已经根据递归版本检查了 1 到 25 的值的结果,它们是相等的。

    请注意,它仍然很慢,因为复杂度是O(2^n),所以它从n=30 开始变得非常慢(当n 增加1 时时间翻倍)。 n=28 在我的笔记本电脑上用了 12 秒计算出来。

    我已经成功地使用此方法解决了在执行洪水填充算法时出现的堆栈溢出问题:Fatal Python error: Cannot recover from stack overflow. During Flood Fill 但这里的 Blcknght 答案更适合,因为它从一开始就重新考虑了计算它的方式。

    【讨论】:

    • 我刚试过,它适用于小数字。但是当你达到 90 岁时,它仍然需要相当长的时间。有什么方法可以加快性能吗?
    • 我发现它现在仍然很慢。将其转换为动态样式的好方法是什么?遗憾的是,我对此并不精通(但至少它指出了要学习的东西!)
    • 即使不是将您的函数转换为迭代,BlckKnght 的回答也快得多。
    • 我现在明白了。我希望我能给你们两个正确的答案,因为你的答案是迭代的,这就是我所要求的,即使他的速度更快。
    • 他的回答也是迭代的。别担心,我得到了 4 票赞成,而且编码很有趣,所以我很好。
    【解决方案3】:

    OP 的函数与 Fibonacci 和 Lucas 函数具有相同的递归结构,只是 f0、f1 和 g 的值不同:

    f(0) = f0
    f(1) = f1
    f(n) = g(f(n-2), f(n-1), n)
    

    这是recurrence relation 的示例。这是一个迭代版本的通用解决方案,它以 n 步计算 f(n)。它对应于自底向上的尾递归。

    def f(n):
        if not isinstance(n, int):  # Can be loosened a bit
            raise TypeError('Input must be an int')  # Can be more informative
        if n < 0:
            raise ValueError('Input must be non-negative')
        if n == 0: 
            return f0
        i, fi_1, fi = 1, f0, f1  # invariant: fi_1, fi = f(i-1), f(i)
        while i < n:
            i += 1
            fi_1, fi = fi, g(fi_1, fi, n)  # restore invariant for new i
        return fi
    

    Blckknight 的回答是这个的简化版

    【讨论】:

      猜你喜欢
      • 2018-10-24
      • 2020-08-08
      • 2015-05-30
      • 1970-01-01
      相关资源
      最近更新 更多