以最小的运行时间存储具有递归的Fibonacci序列的值

时间:2014-07-18 03:21:49

标签: java recursion containers fibonacci

我知道我的代码现在有很多问题,但我只是想在尝试任何事情之前弄清楚这些想法。我需要一个接受整数n的方法,该整数n返回Fibonacci序列中的第n个数字。虽然通过递归正常解决它,但我必须最小化运行时,所以当它得到类似于第45个整数的东西时,它仍然会相当快地运行。另外,我不能使用类常量和全局变量。

正常的递归方式。

public static int fibonacci(int n) {
    if (n <= 2) { // to indicate the first two elems in the sequence 
        return 1;
    } else { // goes back to very first integer to calculate (n-1) and (n+1) for (n)
        return fibonacci(n-1) + fibonacci(n-2); 
    }
}

我认为问题是这个过程中有很多冗余。我想我可以创建一个List来计算最多第n个元素,所以它只在我返回第n个元素之前运行一次。但是,在这种情况下,我无法看到如何使用递归。

如果我理解正确,标准的递归方法很慢,因为有很多重复:

fib(6)= fib(5)+ fib(4)

fib(5)= fib(4)+ fib(3)

fib(4)= fib(3)+ 1

fib(3)= 1 + 1

这是接近这个的正确方法吗?是否需要使用某种形式的容器来获得更快的输出,同时仍然是递归的?我应该使用辅助方法吗?我刚刚进入了递归编程,我很难解决这个问题,因为我已经习惯了迭代方法。感谢。

这是我有缺陷和未完成的代码:

public static int fasterFib(int n) {
    ArrayList<Integer> results = new ArrayList<Integer>();
    if (n <= 2) { // if 
        return 1;
    } else if (results.size() <= n){ // If the list has fewer elems than 
        results.add(0, 1);
        results.add(0, 1);
        results.add(results.get(results.size() - 1 + results.get(results.size() - 2)));
        return fasterFib(n); // not sure what to do with this yet
    } else if (results.size() == n) { // base case if reached elems
        return results.get(n);
    }
    return 0;
}

8 个答案:

答案 0 :(得分:6)

我认为你想使用Map<Integer, Integer>代替List。您可能应该将该集合移出方法之外(因此它可以缓存结果) -

private static Map<Integer, Integer> results = new HashMap<>();

public static int fasterFib(int n) {
  if (n == 0) {
    return 0;
  } else if (n <= 2) { // if
    return 1;
  }
  if (results.get(n) != null) {
    return results.get(n);
  } else {
    int v = fasterFib(n - 1) + fasterFib(n - 2);
    results.put(n, v);
    return v;
  }
}

此优化称为memoization,来自维基百科文章 -

  

在计算中,memoization是一种优化技术,主要用于通过保留昂贵的函数调用的结果来加速计算机程序,并在再次出现相同的输入时返回缓存的结果。

答案 1 :(得分:2)

另一种方法是使用辅助方法。

static private int fibonacci(int a, int b, int n) {
  if(n == 0) return a;
  else return fibonacci(b, a+b, n-1);
}

static public int fibonacci(int n) {
  return fibonacci(0, 1, n);
}

答案 2 :(得分:2)

您可以使用Map :: computeIfAbsent方法(自1.8起)重新使用已计算的数字。

import java.util.HashMap;
import java.util.Map;

public class Fibonacci {

    private final Map<Integer, Integer> cache = new HashMap<>();

    public int fib(int n) {
        if (n <= 2) {
            return n;
        } else {
            return cache.computeIfAbsent(n, (key) -> fib(n - 1) + fib(n - 2));
        }
    }
}

答案 3 :(得分:0)

类和私有静态HashMap怎么样?

import java.util.HashMap;

public class Fibonacci {
    private static HashMap<Integer,Long> cache = new HashMap<Integer,Long>();

    public Long get(Integer n) {
        if ( n <= 2 ) {
            return 1L;
        } else if (cache.containsKey(n)) {
            return cache.get(n);
        } else {
            Long result = get(n-1) + get(n-2);
            cache.put(n, result);
            System.err.println("Calculate once for " + n);
            return result;
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        Fibonacci f = new Fibonacci();
        System.out.println(f.get(10));
        System.out.println(f.get(15));
    }

}

答案 4 :(得分:0)

public class Fibonacci {

    private Map<Integer, Integer> cache = new HashMap<>();


    private void addToCache(int index, int value) {

        cache.put(index, value);


    }

    private int getFromCache(int index) {

        return cache.computeIfAbsent(index, this::fibonacci);

    }


    public int fibonacci(int i) {

        if (i == 1)

            addToCache(i, 0);

        else if (i == 2)
            addToCache(i, 1);
        else
            addToCache(i, getFromCache(i - 1) + getFromCache(i - 2));

        return getFromCache(i);

    }
}

答案 5 :(得分:0)

您可以使用memoization(存储数组中已有的值,如果此数组的给定索引处的值不是您忽略的特定值 - >返回该值)。

代码:

public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    int n = Integer.parseInt(s.nextLine());
    int[] memo = new int[n+1];
    for (int i = 0; i < n+1 ; i++) {
        memo[i] = -1;
    }

    System.out.println(fib(n,memo));


}

static int fib(int n, int[] memo){
    if (n<=1){
        return n;
    }
    if(memo[n] != -1){
        return memo[n];
    }
    memo[n] = fib(n-1,memo) + fib(n-2,memo);
    return memo[n];
}

阐释:

备忘录

 -> int array (all values -1)
 -> length (n+1) // easier for working on index
  1. 您为给定的备忘录索引分配值:memo [2]
  2. 备忘录看起来像[-1,-1,1,.....]
  3. 每当你需要知道2的纤维时,它将返回备忘录[2] - &gt; 1
  4. 这可以节省大量计算时间。

答案 6 :(得分:0)

private static Map<Integer, Integer> cache = new HashMap<Integer, Integer(){
    {
      put(0, 0);
      put(1, 1);
    }
  };
  /**
   * Smallest fibonacci sequence program using dynamic programming.
   * @param n
   * @return
   */
  public static int fibonacci(int n){
    return n < 2 ? n : cache.computeIfAbsent(n, (key) -> fibonacci( n - 1) + fibonacci(n - 2));
  }

答案 7 :(得分:0)

{'key1': (((' value1', 'value2'), 'value3'), 'value4')}