我在哪里看到Recursive Fibonacci系列每个人都告诉
a[i] = fib(i - 1) + fib( i - 2)
但它也可以用
解决a[i] = fib(i - 1) + a[i-2] // If array 'a' is a global variable.
如果数组'a'是全局变量,则在计算[i-2]时会计算[i-2];
可以用java中的以下程序解决..
public class Fibonacci {
public static int maxNumbers = 10;
public static double[] arr = new double[maxNumbers];
public static void main(String args[])
{
arr[0] = 0;
arr[1] = 1;
recur(maxNumbers - 1);
}
public static double recur(int i)
{
if( i > 1)
{
arr[i] = recur(i - 1) + arr[i - 2];
}
return arr[i];
}
}
此外,与原始程序相比,复杂性也更低。这样做有什么不利之处吗?
答案 0 :(得分:4)
你已经完成了Dynamic Programming计算Fibonacci的第一步,DP的想法是避免冗余计算,你的算法实现了它的目标。
“经典”自下而上的DP Fibonacci实现正在填充从低到高的元素:
arr[0] = 0
arr[1] = 1
for (int i = 2; i <= n; i++)
arr[i] = arr[i-1] + arr[i-2]
(优化可以单独存储curr,last
,并在每次迭代时修改它们。
原则上你的方法基本相同。
作为旁注,用于计算斐波那契的DP方法正在花费O(n)
时间,其中存在更有效的矩阵指数解决方案:
1 1
1 0
上述情况适用,因为您使用
这一事实1 1 F_{n+1} 1*F{n+1} + 1*F{n} F_{n+2}
* = =
1 0 F_{n} 1*F{n+1} + 0*F{n} F_{n+1}
在上述矩阵中使用exponent by squaring,可以在O(logn)
中解决此问题。
答案 1 :(得分:2)
如果你只想要第n个斐波纳契数,你可以这样做:
static double fib(double prev, double curr, int n) {
if(n == 0)
return curr;
return fib(curr, prev+curr, n-1);
}
初始条件为prev = 0
,curr = 1
,n = maxNumbers
。此函数是尾递归的,因为您不需要为任何其他计算存储递归调用的返回值。初始堆栈帧被重用(这节省了内存),一旦你遇到你的基本情况,返回的值与从每个其他递归调用返回的值相同。
答案 2 :(得分:1)
您也可以使用两个递归函数进行编码,但是同样的值会反复计算所以您可以执行动态编程方法,您可以存储该值并将其返回到需要的地方。就像在C ++中一样这样做
#include <bits/stdc++.h>
using namespace std;
int dp[100];
int fib(int n){
if(n <= 1)
return n;
if(dp[n]!= -1)
return dp[n];
dp[n] = fib(n-1) + fib(n-2);
return dp[n];
}
int main(){
memset(dp,-1,sizeof(dp));
for(int i=1 ;i<10 ;i++)
cout<<fib(i)<<endl;
}
答案 3 :(得分:1)
通过使用类似于您的数组,您只需重新计算两个分支中的一个(每次迭代中最长的分支),最终会出现O(n)复杂度。
如果你要跟踪你之前已经解决过多大的斐波纳契数,你可以使用它并产生O(max(n-prevn,1))。以下是代码的更改版本,如果需要,可以从底部填充数组:
public class Fibonacci {
public static final int maxNumbers = 93; // fib(93) > Long.MAX_VALUE
public static long[] arr = new long[maxNumbers];
public static int calculatedN = 0;
public static long fib(int i) throws Exception
{
if( i >= maxNumbers )
throw new Exception("value out of bounds");
if( calculatedN == 0 ) {
arr[0] = 0L;
arr[1] = 1L;
calculatedN = 1;
}
if( i > calculatedN ) {
for( int x=calculatedN+1; x<=i; x++ ){
arr[x] = arr[x-2] + arr[x-1];
}
calculatedN = i;
}
return arr[i];
}
public static void main (String args[]) {
try {
System.out.println(fib(50)); // O(50-2)
System.out.println(fib(30)); // O(1)
System.out.println(fib(92)); // O(92-50)
System.out.println(fib(92)); // O(1)
} catch ( Exception e ) { e.printStackTrace(); }
}
}
我改变了双倍长。如果你需要比fib(92)更大的斐波纳契数,我会从长变为Biginteger。
答案 4 :(得分:0)
这只是非递归版本的一步: https://gist.github.com/vividvilla/4641152
一般来说,这种部分递归的方法看起来非常混乱