斐波那契数列 Java 使用递归和循环

⚡ 智能摘要

斐波那契数列 Java 生成一个序列,其中每一项都等于它前面两项之和。本文介绍了 for 循环、while 循环、用户输入、递归和记忆化程序。 traces 递归,并比较每种方法的时间复杂度。

  • 核心规则: 每一项都是前两项之和,数列从 0 和 1 开始。
  • 🔁 迭代模式: 两个变量分别保存前一个值和后一个值,每次迭代时,一个临时求和都会将它们向前移动。
  • 🌀 递归模式: 该方法每个周期调用自身两次,其中 0、1 和 2 作为基本情况。
  • ⏱️ 复杂性差距: 循环的运行时间为 O(n),而朴素递归的运行时间为 O(2ⁿ),但递归在超过大约 40 项后就变得无法使用。
  • 🧠 记忆化修复: 将计算出的项缓存到数组中可以恢复线性时间复杂度,同时保持ping 递归结构。
  • ⚠️ 溢出限制: 第 47 个项超出 int 范围,因此对于更长的序列,需要使用 long 或 BigInteger。
  • ⌨️ 用户输入: Scanner 类在运行时读取所需的计数,而无需更改任何生成逻辑。

斐波那契数列 Java

斐波那契数列是什么 Java?

A 斐波那契系列 in Java 斐波那契数列是一个数字序列,其中下一个数字是前两个数字之和。斐波那契数列的前两个数字是0和1。斐波那契数列在计算两个整数最大公约数的算法的运行时间研究中得到了广泛应用。

The Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...

用公式表示,该规则为 F(n) = F(n-1) + F(n-2),其中 F(0) = 0 且 F(1) = 1。下表显示了前八项是如何生成的。

位置 (n) 计算 价值
0 基本情况 0
1 基本情况 1
2 0 + 1 1
3 1 + 1 2
4 1 + 2 3
5 2 + 3 5
6 3 + 5 8
7 5 + 8 13

斐波那契数列程序 Java 使用 For 循环

迭代版本在任何时刻都只在内存中保留两个值,这就是为什么它的运行时间为线性时间、空间占用为常数。

//Using  For Loop
public class FibonacciExample {
	public static void main(String[] args)
	{
		// Set it to the number of elements you want in the Fibonacci Series
		 int maxNumber = 10;
		 int previousNumber = 0;
		 int nextNumber = 1;
	        System.out.print("Fibonacci Series of "+maxNumber+" numbers:");
	        for (int i = 1; i <= maxNumber; ++i)
	        {
	            System.out.print(previousNumber+" ");
	            /* On each iteration, we are assigning second number
	             * to the first number and assigning the sum of last two
	             * numbers to the second number
	             */


	            int sum = previousNumber + nextNumber;
	            previousNumber = nextNumber;
	            nextNumber = sum;
	        }
	}
}

输出:

Fibonacci Series of 10 numbers:0 1 1 2 3 5 8 13 21 34

程序逻辑:

  • previousNumber 初始化为 0,nextNumber 初始化为 1。
  • 斐波那契循环遍历 maxNumber:
    • 显示上一个数字。
    • 计算前一个数字和下一个数字之和。
    • 更新 previousNumber 和 nextNumber 的新值。

斐波那契数列程序 Java 使用 While 循环

您还可以生成一个 Java 使用斐波那契数列 while 循环 Java运算过程完全相同,只有循环语法有所改变。

//Using  While Loop
public class FibonacciWhileExample {
	public static void main(String[] args)
	{
		 int maxNumber = 10, previousNumber = 0, nextNumber = 1;
	        System.out.print("Fibonacci Series of "+maxNumber+" numbers:");

	        int i=1;
	        while(i <= maxNumber)
	        {
	            System.out.print(previousNumber+" ");
	            int sum = previousNumber + nextNumber;
	            previousNumber = nextNumber;
	            nextNumber = sum;
	            i++;
	        }

	}

}

输出:

Fibonacci Series of 10 numbers:0 1 1 2 3 5 8 13 21 34

程序逻辑的唯一区别在于使用了 while 循环来打印斐波那契数列。计数器必须在循环之前声明,并在循环内部递增,否则循环将永远不会结束。

根据用户输入的斐波那契数列

将词项计数硬编码到代码中便于演示,但实际练习通常会从键盘读取该值。Scanner 类只需三行代码即可完成此操作,生成逻辑保持不变。

//fibonacci series based on the user input
import java.util.Scanner;

public class FibonacciUserInput {

    public static void main(String[] args)
    {
        int maxNumber = 0;
        int previousNumber = 0;
        int nextNumber = 1;

        System.out.println("How many numbers you want in Fibonacci:");
        Scanner scanner = new Scanner(System.in);
        maxNumber = scanner.nextInt();
        System.out.print("Fibonacci Series of " + maxNumber + " numbers:");

        for (int i = 1; i <= maxNumber; ++i)
        {
            System.out.print(previousNumber + " ");
            /* On each iteration, we are assigning the second number
             * to the first number and assigning the sum of the last two
             * numbers to the second number
             */

            int sum = previousNumber + nextNumber;
            previousNumber = nextNumber;
            nextNumber = sum;
        }

        scanner.close();
    }
}

示例运行:

How many numbers you want in Fibonacci:
7
Fibonacci Series of 7 numbers:0 1 1 2 3 5 8

程序逻辑:
逻辑与之前相同。不再硬编码要显示的元素数量, Java 斐波那契数列,要求用户输入一个数字。

斐波那契数列使用递归 Java

下面是一个斐波那契数列程序 Java 使用递归:

//Using Recursion
public class FibonacciCalc{
	public static int fibonacciRecursion(int n){
	if(n == 0){
		return 0;
	}
	if(n == 1 || n == 2){
			return 1;
		}
	return fibonacciRecursion(n-2) + fibonacciRecursion(n-1);
	}
    public static void main(String args[]) {
	int maxNumber = 10;
	System.out.print("Fibonacci Series of "+maxNumber+" numbers: ");
	for(int i = 0; i < maxNumber; i++){
			System.out.print(fibonacciRecursion(i) +" ");
		}
	}
}

输出:

Fibonacci Series of 10 numbers: 0 1 1 2 3 5 8 13 21 34

程序逻辑:

递归函数是具有调用自身的能力的函数。

fibonacciRecursion():

  1. 此 Java 斐波那契递归函数接受一个输入数字。它会检查该数字是否为 0、1 或 2,并分别返回 0、1 或 1,因为斐波那契数列是 2 到 3 的整数。 Java 以 0, 1, 1 开始。
  2. 当输入 n 大于等于 3 时,该函数会递归调用自身。调用次数为两次。 trac下面 e 表示需要输入 4。
fibonacciRecursion(4)
    = fibonacciRecursion(2) + fibonacciRecursion(3)

    fibonacciRecursion(2) = 1                    // base case, no further calls
    fibonacciRecursion(3) = fibonacciRecursion(1) + fibonacciRecursion(2)
                          = 1 + 1
                          = 2

    Result: 1 + 2 = 3

基本情况会阻止递归。因为 1 和 2 都立即返回,所以 fibonacciRecursion(2) 的分支永远不会进一步扩展,这正是保持递归的原因。 trac有限的。

利用记忆化优化斐波那契数列

普通的递归会多次重复计算相同的项。计算第 40 项需要超过 200 亿次的调用。而将每次计算的结果在第一次计算时就存储起来,则可以完全消除这种重复计算。

public class FibonacciMemo {

    static long[] cache;

    public static long fib(int n) {
        if (n <= 1) {
            return n;
        }
        // return the stored value when it exists
        if (cache[n] != 0) {
            return cache[n];
        }
        cache[n] = fib(n - 1) + fib(n - 2);
        return cache[n];
    }

    public static void main(String[] args) {
        int maxNumber = 90;
        cache = new long[maxNumber + 1];

        System.out.println("Term 50 is: " + fib(50));
        System.out.println("Term 90 is: " + fib(90));
    }
}

输出:

Term 50 is: 12586269025
Term 90 is: 2880067194370816120

⚠️警告: 斐波那契数列第 47 项为 2971215073,超过了整数的最大值 2147483647,因此会溢出为负值。当计数超过 46 时,将变量声明为 long 类型;从第 92 项开始,切换到 BigInteger 类型。

斐波那契数列方法的比较 Java

四个程序都打印出相同的序列,因此决定取决于需要多少项。

付款方式 时间复杂度 空间复杂度 实际极限
对于循环 O(N) O(1) 任何计数,受数值类型限制
While循环 O(N) O(1) 任何计数,受数值类型限制
普通递归 O(2ⁿ) O(n) 堆栈 大约40个学期后速度就会变慢。
带记忆化的递归 O(N) O(N) 任何计数,受数值类型限制

相同的计数器和累加器模式出现在几个相关的练习中。继续进行。 Java 回文程序Java 检查质数的程序,并 编写一个程序,打印出 1 到 100 之间的质数。有关基于数组的练习,请参见 Bubble 排序 JavaJava 数组,并审查 对于每个循环 Java 用于其他循环语法。

常见问题

两种惯例都存在。计算机科学通常使用 0 和 1 作为前两个数字,这些程序也是这样做的。而一些数学文献则以 1 和 1 开头。

每次调用都会引发两次后续调用,因此每增加一项,工作量就会翻倍。相同的子问题会被反复求解,从而导致调用次数呈指数级增长。

int 类型最多可以存储 46 位数字,long 类型最多可以存储 92 位数字。超过 92 位后,就需要使用 BigInteger 类型,因为这些值会超过 64 位。

连续的项数接近黄金分割率,约为 1.618。这种模式出现在叶子排列、贝壳螺旋、敏捷评估尺度和交易中的技术分析中。

他们通常返回简单的递归,因为这是教科书中最常见的例子。当项数很多时,应该明确要求使用迭代或记忆化方法。

这是缓存重叠的最小问题ping 子问题处理能够显著提升速度。同样的原理也应用于人工智能规划算法中的记忆化搜索和值缓存。

总结一下这篇文章: