【问题标题】:best way to find Fibonacci number找到斐波那契数的最佳方法
【发布时间】:2017-03-08 16:27:08
【问题描述】:

斐波那契数列是 0 1 1 2 3 5 8... 等等。它可以使用交换元素并显示它们来获得,而我们可以使用数组来获得它。我被要求在面试中使用递归和它的主要逻辑来找到它,

int fib(int n){
if(n<1)
    return 1;
else
    return fib(n-1)+fib(n-2);}

因为我们在这里增加了复杂性,所以它会为大数字的堆栈产生问题。那么这里的最佳方式是什么?

【问题讨论】:

  • 请发布有效的Java代码或更改标签
  • @LuisMuñoz 此代码是我的 java 程序中的方法。该方法对 java 的无效是什么?
  • 使您的代码可以运行更大数字的标准方法是使用很容易在 Java 中实现的 memoization (en.wikipedia.org/wiki/Memoization)。但是——斐波那契数增长得非常快,所以你会很快遇到int 可以容纳的问题,所以你应该改用大整数。另一个想法是让递归辅助函数返回两个连续斐波那契数的pairs——这将消除作为主要问题的双重递归。
  • @RajeshNavagare,您可能是对的,它可能是有效的,但缺少方法范围声明并且可以正确缩进。我们的想法是让与您合作的人的生活更轻松。
  • @JohnColeman 我完全同意你的观点,但我的目的是降低迭代的复杂性。

标签: recursion


【解决方案1】:

具有讽刺意味的是,上面使用的方法,即 二元递归,通过在每个非基本情况下进行两次递归调用来计算斐波那契数。不幸的是,以这种方式直接实现斐波那契公式数字需要对该方法的指数调用次数。

我们很想使用糟糕的递归公式,因为第 n 个斐波那契数 F(n) 取决于前两个值 F(n-2) 和 F(n-1)。但请注意,在计算 F(n-2) 之后,对计算 F(n-1) 的调用需要它自己的递归调用来计算 F(n-2),因为它不知道 F(n- 2)在较早的递归级别计算。那是重复的工作。更糟糕的是,这两个调用都需要(重新)计算 F(n-3) 的值,F(n-1) 的计算也是如此。这种滚雪球效应导致fib() 的运行时间呈指数增长。

我们可以使用 线性递归 更有效地计算 F(n),其中每次调用只进行一次递归调用。为此,我们需要重新定义方法的期望。我们没有使用返回单个值的方法,即第 n 个斐波那契数,而是使用约定 F( -1)=0。尽管报告两个连续的斐波那契数而不是一个似乎是一个更大的负担,但是将这些额外的信息从一个递归级别传递到下一个级别可以使继续该过程变得更加容易。 (它允许我们避免重新计算递归中已知的第二个值。) 基于此策略的实现是clearly shown here.

【讨论】:

    【解决方案2】:

    记忆。创建只计算每个 fib numb 一次的逻辑。

    static BigInteger[] fibNumbs = new BigInteger[10000];
    
    
    public static void main(String[] args) {
            fibNumbs[1] = BigInteger.ONE;
            fibNumbs[2] = BigInteger.ONE;
            System.out.println(fibOf(10000));
        }
    
    public static BigInteger fibOf(int n) {
            if (n <= 1) {
                return BigInteger.ONE;
            }
    
            if (fibNumbs[n - 1]==null) {
                fibNumbs[n - 1] = fibOf(n - 1);
            }
    
            if (fibNumbs[n - 2]==null) {
                fibNumbs[n - 2] = fibOf(n - 2);
            }
    
            return fibNumbs[n - 1].add(fibNumbs[n - 2]);
        }
    

    【讨论】:

    • 我知道这一点。我想要它的代码格式。看到我返回 fib(n-1) 和 fib(n-2) 的加法,其中 fib(n-1) 将在下一次调用中计算 fib(n-2) 需要存储在某个地方以便我可以添加它.所以复杂度会降低。 Array 的三元运算符可以提供帮助,但我期待更好的方法。
    【解决方案3】:

    如果我告诉你两个连续的斐波那契数,例如。 a=3b=5,你能猜到下一个吗?这是两者的总和,所以它是8。现在有了a=5 和新计算的数字b=8,你可以计算下一个吗?您从前两个01 开始迭代,以及您希望为每次迭代倒计时的数字的索引,当您达到零时,a 就是您的答案。这是一个 O(n) 算法。

    【讨论】:

    • 是的,它可以在单个 for 循环和 O(n) 的数组中执行。但是我的要求是使用递归的解决方案,如上所述,复杂性较低。使用递归是堆栈管理的坏习惯,我知道这一点,但我被要求解决这个问题以检查我的优化算法。
    • @RajeshNavagare 当递归调用处于尾部位置并且语言支持尾部调用优化时,循环和递归函数之间没有区别。许多语言都可以,例如。 GNU 对 C++ 的扩展。该算法是相同的,只是不是更新变量,而是将值更新为递归调用,并且变量本质上是绑定参数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 2013-11-21
    • 2020-01-18
    • 2016-11-28
    • 2020-05-24
    相关资源
    最近更新 更多