この簡単なコードを説明してください:
public int fibonacci(int n) {
if(n == 0)
return 0;
else if(n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
特にn = 5の場合、fibonacci(4)+ fibonacci(3)が呼び出されるなどの理由で最後の行と混同しますが、このアルゴリズムがインデックス5の値をどのように計算するかはわかりません。方法。詳しく説明してください!
フィボナッチ数列では、各項目は前の2つの合計です。だから、あなたは再帰的なアルゴリズムを書いた。
そう、
fibonacci(5) = fibonacci(4) + fibonacci(3)
fibonacci(3) = fibonacci(2) + fibonacci(1)
fibonacci(4) = fibonacci(3) + fibonacci(2)
fibonacci(2) = fibonacci(1) + fibonacci(0)
今、あなたはすでにfibonacci(1)==1 and fibonacci(0) == 0
を知っています。そのため、後で他の値を計算できます。
今、
fibonacci(2) = 1+0 = 1
fibonacci(3) = 1+1 = 2
fibonacci(4) = 2+1 = 3
fibonacci(5) = 3+2 = 5
そしてfibonacciシーケンス0,1,1,2,3,5,8,13,21....
から、5th element
に対してfibonacciシーケンスは5
を返すことがわかります。
再帰チュートリアル についてはこちらを参照してください。
コードには2つの問題があります。
fibonacci(n - 1) + fibonacci(n - 2)
非再帰的コードへのアプローチ:
double fibbonaci(int n){
double prev=0d, next=1d, result=0d;
for (int i = 0; i < n; i++) {
result=prev+next;
prev=next;
next=result;
}
return result;
}
擬似コードでは、n = 5の場合、次のようになります。
フィボナッチ(4)+フィボナッチ(3)
これは次のように分類されます。
(fibonacci(3)+ fibonnacci(2))+(fibonacci(2)+ fibonnacci(1))
これは次のように分類されます。
((((fibonacci(2)+ fibonnacci(1))+((fibonacci(1)+ fibonnacci(0))))+((((fibonacci(1)+ fibonnacci(0))+ 1))
これは次のように分類されます。
((((((fibonacci(1)+ fibonnacci(0))+ 1)+ 1)+(1 + 0))+((1 + 0)+ 1)))
これは次のように分類されます。
(((((1 + 0)+ 1)+((1 + 0))+((1 + 0)+ 1)))
5
フィボナッチ数列が1 1 2 3 5 8 ...であるとすると、5番目の要素は5になります。繰り返し.
再帰は時々把握するのが難しい場合があります。一枚の紙でそれを少しだけ評価してください。
fib(4)
-> fib(3) + fib(2)
-> fib(2) + fib(1) + fib(1) + fib(0)
-> fib(1) + fib(0) + fib(1) + fib(1) + fib(0)
-> 1 + 0 + 1 + 1 + 0
-> 3
Javaが実際にこれをどのように評価するかはわかりませんが、結果は同じになります。
以下のように、機能を単純化することもできます。
public int fibonacci(int n) {
if (n < 2) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
F(n)
/ \
F(n-1) F(n-2)
/ \ / \
F(n-2) F(n-3) F(n-3) F(n-4)
/ \
F(n-3) F(n-4)
注意すべき重要な点は、このアルゴリズムは前の計算値の結果を格納しないため指数関数的であるということです。例えばF(n-3)は3回呼ばれます。
詳細はdasguptaの章0.2のアルゴリズムを参照してください。
答えのほとんどは良いもので、フィボナッチの再帰がどのように機能するのかを説明しています。
これは再帰を含む3つのテクニックの分析です。
これが3つすべてをテストするためのコードです。
public class Fibonnaci {
// Output = 0 1 1 2 3 5 8 13
static int fibMemo[];
public static void main(String args[]) {
int num = 20;
System.out.println("By For Loop");
Long startTimeForLoop = System.nanoTime();
// returns the fib series
int fibSeries[] = fib(num);
for (int i = 0; i < fibSeries.length; i++) {
System.out.print(" " + fibSeries[i] + " ");
}
Long stopTimeForLoop = System.nanoTime();
System.out.println("");
System.out.println("For Loop Time:" + (stopTimeForLoop - startTimeForLoop));
System.out.println("By Using Recursion");
Long startTimeRecursion = System.nanoTime();
// uses recursion
int fibSeriesRec[] = fibByRec(num);
for (int i = 0; i < fibSeriesRec.length; i++) {
System.out.print(" " + fibSeriesRec[i] + " ");
}
Long stopTimeRecursion = System.nanoTime();
System.out.println("");
System.out.println("Recursion Time:" + (stopTimeRecursion -startTimeRecursion));
System.out.println("By Using Memoization Technique");
Long startTimeMemo = System.nanoTime();
// uses memoization
fibMemo = new int[num];
fibByRecMemo(num-1);
for (int i = 0; i < fibMemo.length; i++) {
System.out.print(" " + fibMemo[i] + " ");
}
Long stopTimeMemo = System.nanoTime();
System.out.println("");
System.out.println("Memoization Time:" + (stopTimeMemo - startTimeMemo));
}
//fib by memoization
public static int fibByRecMemo(int num){
if(num == 0){
fibMemo[0] = 0;
return 0;
}
if(num ==1 || num ==2){
fibMemo[num] = 1;
return 1;
}
if(fibMemo[num] == 0){
fibMemo[num] = fibByRecMemo(num-1) + fibByRecMemo(num -2);
return fibMemo[num];
}else{
return fibMemo[num];
}
}
public static int[] fibByRec(int num) {
int fib[] = new int[num];
for (int i = 0; i < num; i++) {
fib[i] = fibRec(i);
}
return fib;
}
public static int fibRec(int num) {
if (num == 0) {
return 0;
} else if (num == 1 || num == 2) {
return 1;
} else {
return fibRec(num - 1) + fibRec(num - 2);
}
}
public static int[] fib(int num) {
int fibSum[] = new int[num];
for (int i = 0; i < num; i++) {
if (i == 0) {
fibSum[i] = i;
continue;
}
if (i == 1 || i == 2) {
fibSum[i] = 1;
continue;
}
fibSum[i] = fibSum[i - 1] + fibSum[i - 2];
}
return fibSum;
}
}
結果は次のとおりです。
By For Loop
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
For Loop Time:347688
By Using Recursion
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
Recursion Time:767004
By Using Memoization Technique
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
Memoization Time:327031
したがって、メモ化は時間的に最善の方法であり、forループの一致が厳密に一致することがわかります。
しかし、再帰は最も時間がかかり、現実の世界では避けるべきです。また、再帰を使用している場合は、必ず解を最適化してください。
フィボナッチ再帰的解法では、より大きな数の値を検索しながら、より小さなフィボナッチ数の出力を保存することが重要です。これを「メモ化」と呼びます。
これは小さなフィボナッチ値を記憶しながら大きなフィボナッチ数を取得するコードです。このコードは効率的で、同じ機能を複数回要求することはありません。
import Java.util.HashMap;
public class Fibonacci {
private HashMap<Integer, Integer> map;
public Fibonacci() {
map = new HashMap<>();
}
public int findFibonacciValue(int number) {
if (number == 0 || number == 1) {
return number;
}
else if (map.containsKey(number)) {
return map.get(number);
}
else {
int fibonacciValue = findFibonacciValue(number - 2) + findFibonacciValue(number - 1);
map.put(number, fibonacciValue);
return fibonacciValue;
}
}
}
これは私が見つけた最高のビデオで、Javaでの再帰とフィボナッチ数列を完全に説明しています。
http://www.youtube.com/watch?v=dsmBRUCzS7k
これはシーケンスのための彼のコードであり、彼の説明は私が今までそれをタイプしようと試みることができるよりも優れています。
public static void main(String[] args)
{
int index = 0;
while (true)
{
System.out.println(fibonacci(index));
index++;
}
}
public static long fibonacci (int i)
{
if (i == 0) return 0;
if (i<= 2) return 1;
long fibTerm = fibonacci(i - 1) + fibonacci(i - 2);
return fibTerm;
}
Michael Goodrichらは、[fib(n)、fib(n-1)]の配列を返すことによって線形時間で再帰的にfibonacciを解くための、JavaのData Structures and Algorithmsで本当に賢いアルゴリズムを提供します。
public static long[] fibGood(int n) {
if (n < = 1) {
long[] answer = {n,0};
return answer;
} else {
long[] tmp = fibGood(n-1);
long[] answer = {tmp[0] + tmp[1], tmp[0]};
return answer;
}
}
これにより、fib(n)= fibGood(n)[0]が得られます。
フィボナッチ数列は、前の結果に1から始まる数を加算したものです。
so.. 1 + 1 = 2
2 + 3 = 5
3 + 5 = 8
5 + 8 = 13
8 + 13 = 21
フィボナッチが何であるかを理解したら、コードを分割し始めることができます。
public int fibonacci(int n) {
if(n == 0)
return 0;
else if(n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
最初のif文は、ループが発生する可能性がある基本ケースをチェックします。その下のelse if文も同じことをしていますが、そのように書き直すことができます...
public int fibonacci(int n) {
if(n < 2)
return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
基本的なケースが確立されたので、呼び出しスタックを理解する必要があります。 "fibonacci"への最初の呼び出しは、呼び出された順序とは逆の順序で解決されるので、最後に解決されます。最後に呼び出されたメソッドが最初に解決され、最後に呼び出されたメソッドがその前に呼び出されます。
そのため、すべての呼び出しは、それらの結果を使用して「計算」される前に最初に行われます。入力が8の場合、出力は21になります(上の表を参照)。
fibonacci(n - 1)はベースケースに達するまで呼び出され続け、その後fibonacci(n - 2)はベースケースに達するまで呼び出されます。スタックが逆の順序で結果を合計し始めると、結果は以下のようになります...
1 + 1 = 1 ---- last call of the stack (hits a base case).
2 + 1 = 3 ---- Next level of the stack (resolving backwards).
2 + 3 = 5 ---- Next level of the stack (continuing to resolve).
正しい合計がスタック内の最初の呼び出しに返されるまで、それらはバブリングを続けます(後方への解決)。それがあなたの答えを得る方法です。
そうは言っても、このアルゴリズムは、コードが分割される各ブランチに対して同じ結果を計算するため、非常に非効率的です。もっと良い方法は、メモ化(キャッシング)や再帰(ディープコールスタック)が不要な「ボトムアップ」の方法です。
そのようです...
static int BottomUpFib(int current)
{
if (current < 2) return current;
int fib = 1;
int last = 1;
for (int i = 2; i < current; i++)
{
int temp = fib;
fib += last;
last = temp;
}
return fib;
}
fibonacci シーケンスでは、最初の2つの項目は0と1で、他の各項目は前の2つの項目の合計です。すなわち:
0 1 1 2 3 5 8 ...
5番目の項目は4番目と3番目の項目の合計です。
他のすべての答え:
(さておき、これらのどれも実際には効率的ではありません。nを直接計算するために Binetの公式 を使用番目 期間)
これは、前の回答とその前の回答の両方を渡すことによって二重再帰呼び出しを回避する再帰的アプローチです。
private static final int FIB_0 = 0;
private static final int FIB_1 = 1;
private int calcFibonacci(final int target) {
if (target == 0) { return FIB_0; }
if (target == 1) { return FIB_1; }
return calcFibonacci(target, 1, FIB_1, FIB_0);
}
private int calcFibonacci(final int target, final int previous, final int fibPrevious, final int fibPreviousMinusOne) {
final int current = previous + 1;
final int fibCurrent = fibPrevious + fibPreviousMinusOne;
// If you want, print here / memoize for future calls
if (target == current) { return fibCurrent; }
return calcFibonacci(target, current, fibCurrent, fibPrevious);
}
ここで提供されるソリューションのほとんどは、O(2 ^ n)の複雑さで実行されます。再帰ツリーで同一ノードを再計算することは非効率的であり、CPUサイクルを浪費します。
メモ化を使用して、フィボナッチ関数をO(n)時間内に実行させることができます。
public static int fibonacci(int n) {
return fibonacci(n, new int[n + 1]);
}
public static int fibonacci(int i, int[] memo) {
if (i == 0 || i == 1) {
return i;
}
if (memo[i] == 0) {
memo[i] = fibonacci(i - 1, memo) + fibonacci(i - 2, memo);
}
return memo[i];
}
ボトムアップ動的計画法の経路に従うと、以下のコードはfibonacciを計算するのに十分単純です。
public static int fibonacci1(int n) {
if (n == 0) {
return n;
} else if (n == 1) {
return n;
}
final int[] memo = new int[n];
memo[0] = 0;
memo[1] = 1;
for (int i = 2; i < n; i++) {
memo[i] = memo[i - 1] + memo[i - 2];
}
return memo[n - 1] + memo[n - 2];
}
RanRag(承認済み)回答は問題なく機能しますが、Anil回答で説明されているように記憶されるまでは最適化された解決策ではありません。
以下のアプローチを再帰的に考慮すると、TestFibonacci
のメソッド呼び出しは最小限です。
public class TestFibonacci {
public static void main(String[] args) {
int n = 10;
if (n == 1) {
System.out.println(1);
} else if (n == 2) {
System.out.println(1);
System.out.println(1);
} else {
System.out.println(1);
System.out.println(1);
int currentNo = 3;
calFibRec(n, 1, 1, currentNo);
}
}
public static void calFibRec(int n, int secondLast, int last,
int currentNo) {
if (currentNo <= n) {
int sum = secondLast + last;
System.out.println(sum);
calFibRec(n, last, sum, ++currentNo);
}
}
}
理論的にはこの再帰的実装をマルチスレッド環境で適切に動作させることができる内部ConcurrentHashMapを使用することによって、BigIntegerとRecursionの両方を使用するfib関数を実装しました。最初の100個のfib番号を計算するのに約53msかかります。
private final Map<BigInteger,BigInteger> cacheBig
= new ConcurrentHashMap<>();
public BigInteger fibRecursiveBigCache(BigInteger n) {
BigInteger a = cacheBig.computeIfAbsent(n, this::fibBigCache);
return a;
}
public BigInteger fibBigCache(BigInteger n) {
if ( n.compareTo(BigInteger.ONE ) <= 0 ){
return n;
} else if (cacheBig.containsKey(n)){
return cacheBig.get(n);
} else {
return
fibBigCache(n.subtract(BigInteger.ONE))
.add(fibBigCache(n.subtract(TWO)));
}
}
テストコードは次のとおりです。
@Test
public void testFibRecursiveBigIntegerCache() {
long start = System.currentTimeMillis();
FibonacciSeries fib = new FibonacciSeries();
IntStream.rangeClosed(0,100).forEach(p -&R {
BigInteger n = BigInteger.valueOf(p);
n = fib.fibRecursiveBigCache(n);
System.out.println(String.format("fib of %d is %d", p,n));
});
long end = System.currentTimeMillis();
System.out.println("elapsed:" +
(end - start) + "," +
((end - start)/1000));
}
テストからの出力は 。 。 。 。 。 fib of 93です。 94のfibは、19740274219868223167 95のfibは、31940434634990099905です。 96のfibは、51680708854858323072です。 99のfibは218922995834555169026 100のfibは354224848179261915075 経過:58,0
これは簡単な方法だと思います。
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int number = input.nextInt();
long a = 0;
long b = 1;
for(int i = 1; i<number;i++){
long c = a +b;
a=b;
b=c;
System.out.println(c);
}
}
}
これは、1 1 2 3 5 8 8の出力を表示または取得するのが基本シーケンスです。これは、前の数字と現在の数字の合計が次に表示されるシーケンスです。
Java Recursive Fibonacci sequence Tutorialの下のリンクを見てみてください
public static long getFibonacci(int number){
if(number<=1) return number;
else return getFibonacci(number-1) + getFibonacci(number-2);
}
以下は、1行のフェボナッチ再帰です。
public long fib( long n ) {
return n <= 0 ? 0 : n == 1 ? 1 : fib( n - 1 ) + fib( n - 2 );
}
O(1)ソリューションは次のとおりです。
private static long fibonacci(int n) {
double pha = pow(1 + sqrt(5), n);
double phb = pow(1 - sqrt(5), n);
double div = pow(2, n) * sqrt(5);
return (long) ((pha - phb) / div);
}
ビネのフィボナッチ数式 上記の実装に使用されます。大きな入力の場合、long
はBigDecimal
に置き換えることができます。
while
を使う:
public int fib(int index) {
int tmp = 0, step1 = 0, step2 = 1, fibNumber = 0;
while (tmp < index - 1) {
fibNumber = step1 + step2;
step1 = step2;
step2 = fibNumber;
tmp += 1;
};
return fibNumber;
}
このソリューションの利点は、コードが読みやすく理解しやすいことです。
public class febo
{
public static void main(String...a)
{
int x[]=new int[15];
x[0]=0;
x[1]=1;
for(int i=2;i<x.length;i++)
{
x[i]=x[i-1]+x[i-2];
}
for(int i=0;i<x.length;i++)
{
System.out.println(x[i]);
}
}
}
public class FibonacciSeries {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
for (int i = 0; i <= N; i++) {
int result = fibonacciSeries(i);
System.out.println(result);
}
scanner.close();
}
private static int fibonacciSeries(int n) {
if (n < 0) {
return 1;
} else if (n > 0) {
return fibonacciSeries(n - 1) + fibonacciSeries(n - 2);
}
return 0;
}
}
これを試して
private static int fibonacci(int n){
if(n <= 1)
return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
詳細については、これをチェックアウトする Javaで出力Fibonacciシリーズ - 普通のコード
フィボナッチ数列は、数の結果を合計したもので、前の結果に追加したものです。1から始める必要があります。前の番号と私は位置を変更しました。私は1から15までのフィボナッチ数列を検索しています。
public static void main(String args[]) {
numbers(1,1,15);
}
public static int numbers(int a, int temp, int target)
{
if(target <= a)
{
return a;
}
System.out.print(a + " ");
a = temp + a;
return numbers(temp,a,target);
}
補足するために、もっと大きな数を計算できるようにしたい場合は、BigIntegerを使用してください。
反復的な例です。
import Java.math.BigInteger;
class Fibonacci{
public static void main(String args[]){
int n=10000;
BigInteger[] vec = new BigInteger[n];
vec[0]=BigInteger.ZERO;
vec[1]=BigInteger.ONE;
// calculating
for(int i = 2 ; i<n ; i++){
vec[i]=vec[i-1].add(vec[i-2]);
}
// printing
for(int i = vec.length-1 ; i>=0 ; i--){
System.out.println(vec[i]);
System.out.println("");
}
}
}
http://en.wikipedia.org/wiki/Fibonacci_number 詳細
public class Fibonacci {
public static long fib(int n) {
if (n <= 1) return n;
else return fib(n-1) + fib(n-2);
}
public static void main(String[] args) {
int N = Integer.parseInt(args[0]);
for (int i = 1; i <= N; i++)
System.out.println(i + ": " + fib(i));
}
}
Whileループや他のループを使用する必要がないように、必要なだけシンプルにする