减少阶梯问题亚马逊面试问题的时间复杂度

问题描述

def step(n):
    if (n==0) or (n==1):
        return 1 
    elif n==2:
        return 2
    else:
        return step(n-1) + step(n-2) + step(n-3)
n = int(input())
print(step(n))

对于输入53798080,需要1秒钟。满足测试用例所需的时间要少得多。

解决方法

这种类型的问题-评估递归关系-多年来有很多聪明的人对其进行研究,这意味着您可以使用大量很酷的见解和想法来加快处理速度。

这些注释在确定为什么代码在大量输入时变慢的原因方面做得很好-这是因为您生成了大量重复的递归调用。那么问题是如何解决这个问题。

如果您要保持相同的基本策略,建议您使用memoization。如果您以前没有看过此技术,则基本思想是让递归跟踪已进行的调用并缓存这些调用的结果。然后,如果您尝试两次解决相同的问题,则只需交出缓存的结果即可。

用于记忆的常规模板如下所示。 (它是伪代码,但适应起来应该不太困难。)

def memoized_recursion(original_args,memoization_table):
    if memoization_table contains original_args):
        return memoization_table[original_args]
    else
        # Put the rest of your recursive code here.
        # Before returning a result,store it in memoization_table.

这大大减少了递归调用的次数,从而加快了代码的速度。

当然,这不是使代码更快的唯一解决方案。如果您必须保持递归,则可以使用另一种见解来从根本上改变策略。基本思想是这样。您正在生成一系列看起来像这样的数字:

1,1,2,4,7,13,24,...

这个想法是

  • 前三个词是1、1、2;
  • 此后的每一项是前三个数字的总和;和
  • 您想要该系列的第n个术语。

如果您需要术语0、1或2,则只需阅读答案即可,因为您知道前三个数字。

如果没有,这是您可以使用的另一种技术。使用这个有用的事实,而不是获取之前的三个值并将它们加在一起:使用以1、1、2开头的序列的第n个项等效于以开头的序列的第(n-1)个项1、2、4(你明白为什么吗?)

更一般而言,如果系列的前三个项分别是a,b和c,而您想要第n个项,则可以要求序列的第(n-1)个从序列b,c开始的项,a + b + c。这提供了一种不同的递归策略,其中递归不分支,这意味着您不需要记忆。

现在,最后一个策略。您要解决的问题类型涉及称为 齐次线性递归关系 的问题。也就是说,您重复使用该表格

  • a 0 ,a 1 ,...和a k-1 是固定常数,并且
  • a n + k = c 0 a n + c 1 a n + 1 + ... + c k-1 a n + k-1

这种重复发生包括斐波那契数列,佩尔数,帕多万序列等。

事实证明,在任何情况下,如果您要解决此类递归问题,都可以通过将特定选择的矩阵提升为特定幂来解决问题。在您的情况下,基本思想与第二种递归策略有关。这个想法是,如果序列的最后三个项是a,b和c,则您知道下一个项是a + b + c,而在此之前的两个项是b和c。换句话说,您可以想到将(a,b,c)变成(b,c,a + b + c)的映射。可以认为是这个矩阵方程:

| 0  1  0 | |a|   |     b     |
| 0  0  1 | |b| = |     c     |
| 1  1  1 | |c|   | a + b + c |

如果让M为最左边的矩阵,则计算Mn并将其乘以列向量(a,b,c)将得到第n个,第(n + 1)个和(n + 2)循环关系的术语。这给出了解决问题的完全不同的策略:建立矩阵,然后将其提高到更大的幂!

实际上,您可以非常高效地执行此操作。有一种称为exponentiation by squaring的(递归)技术可以仅使用O(log n)乘法来计算矩阵的n次幂。 (不幸的是,矩阵的条目将开始变得很大,将它们相乘将成为您的瓶颈)。不过,由于这是一种非常酷的技术,可能值得研究一下该策略!

最后,最后一个选择。如果您执行Google搜索,您会发现问题与找到第n个tribonacci number密切相关。您可以使用一些很酷的公式直接计算出该公式,还涉及数字的幂,尽管它们可能会引入一些舍入错误,从而使事情变慢了很多。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...