斐波那契算法

本文介绍了斐波那契数列的定义及其在数学、生物学和艺术设计中的应用,重点展示了如何在Java中使用递归、迭代和矩阵快速幂方法计算数列。文章还讨论了如何将斐波那契数列应用于在线购物网站的推荐系统,以决定商品展示顺序。
摘要由CSDN通过智能技术生成

斐波那契数列

斐波那契数列(Fibonacci sequence)是一个非常著名的数学序列,它是由意大利数学家莱昂纳多·斐波那契(Leonardo Fibonacci)在1202年的著作《计算之书》(Liber Abaci)中首次引入的。这个数列的定义如下:

  1. 数列的前两个数是 0 和 1。
  2. 从第三个数开始,每个数都是前两个数的和。

用数学公式表示,斐波那契数列可以写成:

F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2) 对于 n > 1 的所有自然数 n。

斐波那契数列的前几个数是:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

这个数列在数学、科学、艺术和自然界中都有广泛的应用。例如,在生物学中,许多植物的生长模式(如菠萝的鳞片排列、向日葵的种子排列)遵循斐波那契数列。在艺术和设计中,黄金分割比例(Golden Ratio),也称为黄金比例(Golden Proportion),大约是1.618,这个比例与斐波那契数列紧密相关。

斐波那契数列的第n项可以通过递归、迭代或使用闭式公式(Binet’s Formula)来计算。闭式公式如下:

F(n) = (φ^n - (-φ)^-n) / sqrt(5)

其中,φ (phi) 是黄金比例,约等于1.618033988749895…,是(1 + sqrt(5)) / 2 的结果。这个公式可以直接计算出数列的任意一项,而不需要计算前面的所有项。

Java语言书写

在Java语言中,实现斐波那契数列可以通过多种方法,包括递归、迭代和使用矩阵快速幂。以下是这三种方法的详细实现:

  1. 递归方法
    递归方法是最直接的实现方式,但它的效率不高,因为会有很多重复的计算。
public class Fibonacci {

    public static int fibonacciRecursive(int n) {
        if (n <= 1) {
            return n;
        } else {
            return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
        }
    }

    public static void main(String[] args) {
        int n = 10; // 计算前10项
        for (int i = 0; i < n; i++) {
            System.out.print(fibonacciRecursive(i) + " ");
        }
    }
}
  1. 迭代方法
    迭代方法效率更高,因为它避免了重复计算。
public class Fibonacci {

    public static int fibonacciIterative(int n) {
        if (n <= 1) {
            return n;
        }
        int fib = 1;
        int prevFib = 1;
        for (int i = 2; i < n; i++) {
            int temp = fib;
            fib += prevFib;
            prevFib = temp;
        }
        return fib;
    }

    public static void main(String[] args) {
        int n = 10; // 计算前10项
        for (int i = 0; i < n; i++) {
            System.out.print(fibonacciIterative(i) + " ");
        }
    }
}
  1. 矩阵快速幂方法(Binet’s Formula):
    这种方法利用了斐波那契数列的闭式公式,通过矩阵乘法快速计算。
public class Fibonacci {

    public static int fibonacciMatrix(int n) {
        if (n == 0) {
            return 0;
        }
        int m = (int) Math.pow(5, 0.5);
        int[][] result = {{1, 1}, {1, 0}};
        int[][] base = {{1, 1}, {1, 0}};
        while (n > 0) {
            if (n % 2 == 1) {
                multiply(result, base, result);
            }
            multiply(base, base, base);
            n /= 2;
        }
        return result[0][0];
    }

    private static void multiply(int[][] a, int[][] b, int[][] result) {
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                result[i][j] = 0;
                for (int k = 0; k < 2; k++) {
                    result[i][j] += (long)a[i][k] * b[k][j] % m;
                }
            }
        }
    }

    public static void main(String[] args) {
        int n = 10; // 计算第10项
        System.out.println(fibonacciMatrix(n));
    }
}

在这个例子中,我们使用了黄金比例的平方根(m)来取模,以避免在计算过程中出现大数。这种方法的时间复杂度是O(log n),因为它基于二分法。

请注意,由于Java的整数类型(int)在处理大数时可能会溢出,所以在实际应用中,你可能需要使用long类型或者Java的BigInteger类来处理更大的斐波那契数。

需求场景:一个在线购物网站

一个在线购物网站想要在商品详情页面展示一个“推荐商品”区域,该区域会根据用户浏览的商品推荐相似的商品。为了实现这个功能,网站决定使用斐波那契数列来决定推荐商品的顺序,即推荐商品的顺序基于斐波那契数列的索引。例如,如果用户正在查看索引为5的商品(从0开始计数),那么推荐系统会推荐索引为3(F(3)=2)、2(F(2)=1)、1(F(1)=1)的商品。

解决步骤:

  1. 创建一个Java方法来生成斐波那契数列的前N项。
  2. 在商品详情页面的后端逻辑中,使用这个方法来获取推荐商品的索引。
  3. 根据这些索引从数据库中检索推荐商品并展示在页面上。

以下是实现这个需求的Java代码示例:

import java.util.ArrayList;
import java.util.List;

public class FibonacciRecommendation {

    // 生成斐波那契数列的前N项
    public static List<Integer> generateFibonacci(int N) {
        List<Integer> fibonacciSeries = new ArrayList<>();
        int a = 0, b = 1, c = 0;

        // 初始化前两项
        fibonacciSeries.add(a);
        if (N > 1) {
            fibonacciSeries.add(b);
        }

        // 计算剩余的项
        for (int i = 2; i < N; i++) {
            c = a + b;
            fibonacciSeries.add(c);
            a = b;
            b = c;
        }

        return fibonacciSeries;
    }

    // 获取推荐商品的索引
    public static List<Integer> getRecommendedIndices(int currentProductIndex, int N) {
        List<Integer> recommendedIndices = new ArrayList<>();

        // 获取斐波那契数列
        List<Integer> fibonacciSeries = generateFibonacci(N);

        // 计算推荐商品的索引
        for (int index : fibonacciSeries) {
            if (index <= currentProductIndex) {
                recommendedIndices.add(currentProductIndex - index);
            }
        }

        return recommendedIndices;
    }

    // 主方法,用于测试
    public static void main(String[] args) {
        // 假设用户正在查看索引为5的商品
        int currentProductIndex = 5;
        int N = 10; // 推荐商品的数量

        // 获取推荐商品的索引
        List<Integer> indices = getRecommendedIndices(currentProductIndex, N);

        // 输出推荐商品的索引
        System.out.println("推荐商品的索引:" + indices);
    }
}

在这个例子中,generateFibonacci方法用于生成斐波那契数列的前N项。getRecommendedIndices方法接受当前商品的索引和推荐商品的数量N,然后返回一个推荐商品的索引列表。在main方法中,我们测试了这个逻辑,假设用户正在查看索引为5的商品,并获取了推荐商品的索引。

请注意,这个例子是一个简化的版本,实际应用中可能需要考虑商品数据库的查询逻辑、用户偏好、商品的相似度等因素。此外,为了避免索引越界,实际应用中可能需要对推荐逻辑进行更复杂的处理。

需求:兔子问题(斐波那契数列)。

有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?由此可见兔子对象的数据是:1 , 1 , 2 , 3 , 5 , 8 …

首先我们对其数据进行分析,可知从第三天开始,每天的兔子数量等于前两天之和,其次我们要知道递归的思想:
递归:在方法中调用方法本身的现象。注意事项:1.递归要有出口 2.递归次数不宜过多 3.递归所体现的思想,就是拆分合并的思想
public static void main(String[] args) {
        //定义一个方法去实现逻辑,传入月数并接收其返回值
        int sum = sumRabbit(20);
        //打印结果
        System.out.println("兔子的对数为:" + sum);
    }

    private static int sumRabbit(int i) {
        //判断传来的月数是不是第1个月或者两个月,如果是则返回1
        if (i == 1 || i == 2) {
            return 1;
        } else {
            //如果传来的月数不是1或者2,那么返回前两个月兔子数量的和;这里采用了递归的思想
            return sumRabbit(i - 1) + sumRabbit(i - 2);
        }
    }

public class Demo5_2 {
    public static void main(String[] args) {
        System.out.println(fibonacci(5));
    }

    /**
     * 计算斐波那契数列  黄金分割线
     * @param month
     * @return
     */
    public static int fibonacci(int month){
//        第一   1
//        第二   1
//        第三   2   第一月+ 第二月
//        第四月  3   第二月+ 第三月
//        第五月  5
//        第n月   ?   第n-1 + 第n-2
//        创建数组
        int[] arr = new int[month];
        arr[0] = 1;
        arr[1] = 1;
        for (int i = 2; i < arr.length; i++) {
            arr[i] = arr[i-1]+ arr[i-2];
        }

        System.out.println(Arrays.toString(arr));
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum;
    }
}
  • 18
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

InnovatorX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值