私はJava 8.でラムダ式機能を使用する初心者です。ラムダ式は素数チェック、階乗などのプログラムを解くのに非常に便利です。
ただし、現在の値が前の2つの値の合計に依存するフィボナッチのような問題を解決する際に効果的に利用できますか。 Lambda式を使用して素数チェックの問題を効果的に解決しました。同じもののコードを以下に示します。
boolean checkPrime=n>1 && LongStream.range(2, (long) Math.sqrt(n)).parallel().noneMatch(e->(n)%e==0);
上記のnoneMatch
メソッドのコードでは、範囲内の現在の値(e
)で評価しています。しかし、フィボナッチ問題では、前の2つの値が必要です。
どうすれば実現できますか?
最も簡単な解決策は、Pair
sのストリームを使用することです。
_Stream.iterate(new long[]{ 1, 1 }, p->new long[]{ p[1], p[0]+p[1] })
.limit(92).forEach(p->System.out.println(p[0]));
_
標準のペアタイプがないため、2要素の配列を使用します。さらに、long
値を使用してこれ以上の要素を評価できないため、.limit(92)
を使用しています。しかし、BigInteger
への適応は簡単です。
_Stream.iterate(new BigInteger[]{ BigInteger.ONE, BigInteger.ONE },
p->new BigInteger[]{ p[1], p[0].add(p[1]) })
.forEach(p->System.out.println(p[0]));
_
これは、次の値を表すのに十分なメモリがなくなるまで実行されます。
ところで、ストリームからn番目の要素を取得するには:
_Stream.iterate(new long[]{1, 1}, p -> new long[]{p[1], p[0] + p[1]})
.limit(91).skip(90).findFirst().get()[1];
_
N番目のフィボナッチ要素を取得するには(リダクションを使用):
Stream.iterate(new long[] {1, 1}, f -> new long[] {f[1], f[0] + f[1]})
.limit(n)
.reduce((a, b) -> b)
.get()[0];
これが起こっていることです:
Stream.iterate()-それぞれがフィボナッチの2つの連続した要素を含む数値のペアを生成しています。 2つ以上の前の要素ではなく、「反復」を介して最後の要素にのみアクセスできるため、ペアを使用する必要があります。新しいペアを生成するには、フィボナッチの以前の2つの要素が既に含まれている最後のペアを取得し、次のペア。そして、K番目のフィボナッチ要素を取得するには、K番目のペアから左の値を取得する必要があります。
。limit(n)-最初のNペアを保持し、残りを除外します。
。reduce((a、b)-> b)-前のステップのNペアのストリームから最後のペアを取得します。
。get()[0]-ペアからフィボナッチ要素を抽出します(ペアの左側の値)
フィボナッチを解く(非再帰的方法)
これはあなたのアプローチでは起こりません
前の2つの数値に基づくフィボナッチ数の生成は前の2つの数値に基づくです。つまり、再帰せずにループで実装したとしても、これは再帰的なアルゴリズムです。
行列指数に基づく他の方法があるため、n-1個の以前の数を計算せずにn番目のフィボナッチ数を計算できますが、問題(系列の計算)の場合、これは意味がありません。
つまり、最後に質問に答えるために、前の2つの要素でラムダ式をどのように使用できますか?:それぞれが含まれているタプルのリストがあります2つの連続した番号、それを繰り返し、ステップごとに新しいタプルを追加します。
ラムダ式で変数を使用して、前の要素を一時的に格納できます。これは、フィボナッチ数列の次の要素を計算するために必要です。
public class FibonacciGenerator {
private long prev=0;
public void printSequence(int elements) {
LongStream.iterate(1, n -> {n+=prev; prev=n-prev; return n;}).
limit(elements).forEach(System.out::println);
}
}
通常、メソッドとフィールドはむしろ静的として宣言されますが、インスタンスフィールドも使用できることを示したいと思いました。
フィールドの代わりにローカル変数(メソッドで宣言された、またはメソッドに渡された)を使用できないことに注意してください。これらの変数はラムダで使用するためにfinalである必要があるためです。この目的のために、反復中にさまざまな値を格納するための可変変数が必要でした。
非再帰的な実装でフィボナッチ数列のn番目の数を検索する場合は、次の式を使用できます。
Un = ( (1+sqrt(5))^n - (1-sqrt(5))^n ) / (2^n * sqrt(5))
long fibonacci(int n) {
return (long) ((Math.pow(1 + Math.sqrt(5), n) - Math.pow(1 - Math.sqrt(5), n)) /
(Math.pow(2, n) * Math.sqrt(5)));
}