递归是否需要在楼梯问题中自底向上进行记忆化?

时间:2019-06-23 14:07:27

标签: algorithm topdown bottom-up

将经典楼梯问题视为“戴维斯的房子里有许多楼梯,他喜欢一次爬上1、2或3个台阶。作为一个非常早熟的孩子,他想知道有多少种方法,到达楼梯的顶部。”

我的方法是将回忆与递归配合使用

# TimeO(N), SpaceO(N), DP Bottom Up + Memoization
def stepPerms(n, memo = {}):

    if n < 3:
        return n
    elif n == 3:
        return 4

    if n in memo:
        return memo[n]
    else:
        memo[n] = stepPerms(n - 1, memo) + stepPerms(n - 2 ,memo) + stepPerms(n - 3 ,memo)
        return memo[n]

我想到的问题是,此解决方案是自下而上还是自上而下。我的解决方法是,因为我们一直向下计算上限N个值(想象一下递归树)。我认为这是自下而上的。这是正确的吗?

2 个答案:

答案 0 :(得分:1)

无论有无记忆力,退缩策略通常都是自上而下的方法。底层算法设计是动态编程,传统上是以自下而上的方式构建的。

我注意到您是用python编写代码的,而python通常对深度回避不满意(少量也可以,但是性能很快受到打击,最大回覆深度为1000-除非自从阅读)。

如果我们创建一个自底向上的动态programmin版本,则可以摆脱这种重复,并且我们还可以认识到我们只需要恒定的空间,因为我们仅对最后三个值感兴趣:

def stepPerms(n):
    if n < 1: return n
    memo = [1,2,4]
    if n <= 3: return memo[n-1]

    for i in range(3,n):
        memo[i % 3] = sum(memo)
    return memo[n-1]

请注意,逻辑简单得多,i位置的appart比值小1,因为位置从0开始而不是从1开始计数。

答案 1 :(得分:0)

在自上而下的方法中,复杂模块分为子模块。因此,这是自上而下的方法。另一方面,自下而上的方法从基本模块开始,然后进一步将它们组合在一起。

此解决方案的自底向上方法将是:

memo{}

for i in range(0,3):
   memo[i]=i
memo[3]=4

for i in range(4,n+1):
  memo[i]=memo[i-1]+memo[i-2]+memo[i-3]