Java Fibonacci Sequence快速方法

时间:2016-10-03 20:12:00

标签: java fibonacci

我需要一个关于在Java中为我的独立项目寻找Fibonacci序列的任务。以下是查找方法。

private static long getFibonacci(int n) {
    switch (n) {
        case 0:
            return 0;
        case 1:
            return 1;
        default:
            return (getFibonacci(n-1)+getFibonacci(n-2));
    }
}

private static long getFibonacciSum(int n) {
    long result = 0;

    while(n >= 0) {
        result += getFibonacci(n);
        n--;
    }
    return result;
}

private static boolean isInFibonacci(long n) {
    long a = 0, b = 1, c = 0;

    while (c < n) {
        c = a + b;
        a = b;
        b = c;
    }

    return c == n;
}

这是主要方法:

    long key = getFibonacciSum(n);
    System.out.println("Sum of all Fibonacci Numbers until Fibonacci[n]: "+key);

    System.out.println(getFibonacci(n)+" is Fibonacci[n]");

    System.out.println("Is n2 in Fibonacci Sequence ?: "+isInFibonacci(n2));

代码完全完成并正常工作。但是如果n或n2将超过正常值(Fib.Seq。中的第50个数字)?代码将会耗尽。有什么建议吗?

6 个答案:

答案 0 :(得分:5)

有一种方法可以使用 Binet公式

即时计算斐波那契数字

<强> 算法:

function fib(n):
   root5 = squareroot(5)
   gr = (1 + root5) / 2
   igr = 1 - gr
   value = (power(gr, n) - power(igr, n)) / root5

   // round it to the closest integer since floating 
   // point arithmetic cannot be trusted to give
   // perfect integer answers. 
   return floor(value + 0.5) 

完成此操作后,您需要了解您正在使用的编程语言及其行为方式。这可能会返回浮点十进制类型,而整数可能是期望的。

  

此解决方案的复杂性为O(1)。

答案 1 :(得分:2)

这种解决方案称为动态编程

  1. 在这种方法中,我们记住以前的结果
  2. 所以当递归发生时,cpu不必再做任何工作来一次又一次地重新计算相同的值

    class fibonacci
    {
    static int fib(int n)
     {
    /* Declare an array to store Fibonacci numbers. */
       int f[] = new int[n+1];
       int i;
    
       /* 0th and 1st number of the series are 0 and 1*/
       f[0] = 0;
       f[1] = 1;
    
       for (i = 2; i <= n; i++)
       {
           /* Add the previous 2 numbers in the series
            and store it */
           f[i] = f[i-1] + f[i-2];
        }
    
        return f[n];
      }
    
    public static void main (String args[])
        {
           int n = 9;
           System.out.println(fib(n));
        }
    }
    

答案 2 :(得分:1)

是的,您可以做的一项改进是getFibonacciSum():而不是一次又一次地调用isInFibonacci从头开始重新计算所有内容,您可以执行与{{1}完全相同的操作正在做并在一次通过中获得总和,如:

isInFibonacci

答案 3 :(得分:1)

好吧,这是我使用 Map 和 { { F(2k) = F(k)[2F(k+1)−F(k)] }, { F(2k+1) = F(k +1)^2+F(k)^2 } }。 (公式来源:https://www.nayuki.io/page/fast-fibonacci-algorithms

也可以使用列表而不是地图来实现它,但这只是在重新发明轮子。

在使用Iteration方案的时候,我们不用担心内存不足,但是比如获取fib(1000000)需要很多时间。在这个解决方案中,对于非常非常非常大的输入(例如 100000 亿,idk),我们可能会耗尽内存,但速度要快得多。

public BigInteger fib(BigInteger n) {
    if (n.equals(BigInteger.ZERO))
        return BigInteger.ZERO;
    if (n.equals(BigInteger.ONE) || n.equals(BigInteger.valueOf(2)))
        return BigInteger.ONE;
    
    BigInteger index = n;
    
    //we could have 2 Lists instead of a map
    Map<BigInteger,BigInteger> termsToCalculate = new TreeMap<BigInteger,BigInteger>();
    
    //add every index needed to calculate  index n
    populateMapWhitTerms(termsToCalculate, index);
    
    termsToCalculate.put(n,null); //finally add n to map
    
    Iterator<Map.Entry<BigInteger, BigInteger>> it = termsToCalculate.entrySet().iterator();//it 
    it.next(); //it = key number 1, contains fib(1);
    it.next(); //it = key number 2, contains fib(2);
    
    //map is ordered
    while (it.hasNext()) {
        Map.Entry<BigInteger, BigInteger> pair = (Entry<BigInteger, BigInteger>)it.next();//first it = key number 3
        index = (BigInteger) pair.getKey();
        
        if(index.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
            //index is divisible by 2
            //F(2k) = F(k)[2F(k+1)−F(k)]
            pair.setValue(termsToCalculate.get(index.divide(BigInteger.valueOf(2))).multiply(
                    (((BigInteger.valueOf(2)).multiply(
                            termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)))).subtract(
                                    termsToCalculate.get(index.divide(BigInteger.valueOf(2)))))));
        }
        else {
            //index is odd
            //F(2k+1) = F(k+1)^2+F(k)^2
            pair.setValue((termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)).multiply(
                    termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)))).add(
                            (termsToCalculate.get(index.divide(BigInteger.valueOf(2))).multiply(
                            termsToCalculate.get(index.divide(BigInteger.valueOf(2))))))
                    );
        }
    }
    
    // fib(n) was calculated in the while loop
    return termsToCalculate.get(n);
}

private void populateMapWhitTerms(Map<BigInteger, BigInteger> termsToCalculate, BigInteger index) {
    if (index.equals(BigInteger.ONE)) { //stop
        termsToCalculate.put(BigInteger.ONE, BigInteger.ONE);
        return;
        
    } else if(index.equals(BigInteger.valueOf(2))){
        termsToCalculate.put(BigInteger.valueOf(2), BigInteger.ONE);
        return;
        
    } else if(index.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
        // index is divisible by 2
        // FORMUMA: F(2k) = F(k)[2F(k+1)−F(k)]
                    
        // add F(k) key to termsToCalculate (the key is replaced if it is already there, we are working with a map here)
        termsToCalculate.put(index.divide(BigInteger.valueOf(2)), null);
        populateMapWhitTerms(termsToCalculate, index.divide(BigInteger.valueOf(2)));

        // add F(k+1) to termsToCalculate
        termsToCalculate.put(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE), null);
        populateMapWhitTerms(termsToCalculate, index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE));
        
    } else {
        // index is odd
        // FORMULA: F(2k+1) = F(k+1)^2+F(k)^2

        // add F(k+1) to termsToCalculate
        termsToCalculate.put(((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)).add(BigInteger.ONE)),null);
        populateMapWhitTerms(termsToCalculate,((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)).add(BigInteger.ONE)));

        // add F(k) to termsToCalculate
        termsToCalculate.put((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)), null);
        populateMapWhitTerms(termsToCalculate, (index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)));
    }
    
}

答案 4 :(得分:0)

public static long getFib(final int index) {
        long a=0,b=0,total=0;
        for(int i=0;i<= index;i++) {
                if(i==0) {
                     a=0;
                     total=a+b;
                 }else if(i==1) {
                     b=1;
                     total=a+b;
                 }

            else if(i%2==0) {
                total = a+b;
                a=total;                
            }else {
                total = a+b;
                b=total;
            }

        }
        return total;
    }

答案 5 :(得分:-1)

直接递归实现可以达到50或略低于50。如果你想要远高于此,你可以切换到迭代或动态编程(DP)方法。我建议从中学习:https://www.javacodegeeks.com/2014/02/dynamic-programming-introduction.html。并且不要忘记在David的评论中查看解决方案,真正有效。链接显示了如何使用DP方法即时计算n = 500000。该链接还解释了“memoization”的概念,通过存储中间(但稍后可重新调用)结果来加速计算。