我是Java 8中使用Lambda表达式功能的初学者.Lambda表达式在解决Prime数字检查,阶乘等程序方面非常有用。
然而,它们可以有效地用于解决像Fibonacci这样的问题,其中当前值取决于前两个值的总和。我已经很好地使用Lambda表达式有效地解决了素数检查问题。下面给出了相同的代码。
boolean checkPrime=n>1 && LongStream.range(2, (long) Math.sqrt(n)).parallel().noneMatch(e->(n)%e==0);
在noneMatch
方法的上述代码中,我们使用范围中的当前值(e
)进行评估。但对于Fibonacci问题,我们需要前两个值。
我们怎样才能实现?
答案 0 :(得分:30)
最简单的解决方案是使用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]));
由于缺少标准对类型,它使用双元素阵列。此外,我使用.limit(92)
,因为我们无法使用long
值评估更多元素。但很容易适应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]));
直到你没有足够的内存来表示下一个值时才会运行。
BTW,从流中获取第n个元素:
Stream.iterate(new long[]{1, 1}, p -> new long[]{p[1], p[0] + p[1]})
.limit(91).skip(90).findFirst().get()[1];
答案 1 :(得分:4)
获得第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个先前的斐波纳契元素,并产生 下一对。为了获得Kth斐波那契元素,我们只需要 从第K对得到左值。
.limit(n) - 保留前N对,并排除其余部分。
.reduce((a,b) - > b) - 从上一步的N对流中获取最后一对。
.get()[0] - 从对中提取斐波纳契元素(该对的左侧值)
答案 2 :(得分:3)
解决斐波纳契(非递归方式)
您的方法不会发生这种情况
基于前两个数字的Fibonacci数的生成是基于前两个数字,即它是一个递归算法,即使你在没有递归但是在循环中实现它。
还有基于矩阵指数的其他方法,因此您可以计算第n个斐波那契数而不计算前面的n-1数,但对于您的问题(计算系列),这并不是&#39有意义。
那么,最后回答你的问题,即如何在前两个元素上使用Lambda表达式?:有一个元组列表,每个元组包含两个连续的数字,并迭代,每一步都添加一个新的元组。
答案 3 :(得分:0)
如果你想要一个非递归的实现来找到第n个Fibonacci序列,你可以使用公式:
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)));
}
答案 4 :(得分:0)
您可以在lambda表达式中使用变量来临时存储前一个元素,这是计算斐波纳契序列中下一个元素所必需的。
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);
}
}
通常,方法和字段宁愿声明为静态,但我想表明实例字段也可以使用。
请注意,您不能使用局部变量(在方法中声明或传递给方法)代替字段,因为此类变量必须是最终变量才能在lambda中使用。为此,我们需要一个可变变量来在迭代过程中存储不同的值。
答案 5 :(得分:0)
我知道这是一个老问题,但是我觉得值得提出更多使用Pair<>
的方法,并且我提出了两种使用Stream
API的方法。
//calculate Fibonacci at given place
public static long fibonacciAt(int place) {
Pair<Integer, Integer> seed = new Pair<>(0, 1);
//return Stream.iterate(seed, feed -> new Pair<>(feed.getValue(), feed.getValue() + feed.getKey())).limit(place).reduce((integerIntegerPair, integerIntegerPair2) -> integerIntegerPair2).orElse(seed).getValue();
return Stream.iterate(seed, feed -> new Pair<>(feed.getValue(), feed.getValue() + feed.getKey())).limit(place).skip(place-1).findFirst().orElse(seed).getValue();
}
使用reduce
的注释的return语句也可以正常工作。
后面的return语句是跳过对数直到place
变量。(这是因为我们没有findLast()
方法)。