用于解决fibonacci的Java 8 Lambda表达式(非递归方式)

时间:2015-06-02 12:16:35

标签: java lambda functional-programming java-8 java-stream

我是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问题,我们需要前两个值。

我们怎样才能实现?

6 个答案:

答案 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))

Binet's Fibonacci Number Formula

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()方法)。