斐波那契数列
斐波那契数列(Fibonacci sequence)是一个非常著名的数学序列,它是由意大利数学家莱昂纳多·斐波那契(Leonardo Fibonacci)在1202年的著作《计算之书》(Liber Abaci)中首次引入的。这个数列的定义如下:
- 数列的前两个数是 0 和 1。
- 从第三个数开始,每个数都是前两个数的和。
用数学公式表示,斐波那契数列可以写成:
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语言中,实现斐波那契数列可以通过多种方法,包括递归、迭代和使用矩阵快速幂。以下是这三种方法的详细实现:
- 递归方法:
递归方法是最直接的实现方式,但它的效率不高,因为会有很多重复的计算。
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) + " ");
}
}
}
- 迭代方法:
迭代方法效率更高,因为它避免了重复计算。
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) + " ");
}
}
}
- 矩阵快速幂方法(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)的商品。
解决步骤:
- 创建一个Java方法来生成斐波那契数列的前N项。
- 在商品详情页面的后端逻辑中,使用这个方法来获取推荐商品的索引。
- 根据这些索引从数据库中检索推荐商品并展示在页面上。
以下是实现这个需求的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;
}
}