编程之美2.9 斐波那契数列

本文介绍了四种不同的斐波那契数列计算方法,包括递归、存储中间结果、利用通项公式和矩阵相乘的方式。通过这些方法,可以有效地减少计算时间和资源消耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// 题目:斐波那契数列
// 解法1:用递归的方式完成
public class Main {

	public static void main(String[] args) throws Exception {
		System.out.println(fib(998));
	}

	public static int fib(int n) {
		if (n <= 0) { // 如果n小于等于0就返回0
			return 0;
		}
		if (n == 1) { // 如果n等于1就返回1
			return 1;
		}
		return fib(n - 1) + fib(n - 2); // 否则进行递归
	}

}

// 解法2:存储中间结果,避免了了大量的重复计算,可以使用递归或非递归完成
public class Main {

	private static int[] arr = new int[999];

	public static void main(String[] args) throws Exception {
		System.out.println(fib1(998));
		System.out.println(fib2(998));
	}

	// 非递归的方式完成
	public static int fib1(int n) {
		if (n <= 0) {
			return 0;
		} else if (n == 1) {
			return 1;
		}
		int temp = 1;
		int num1 = 0;
		int num2 = 1;
		while (temp != n) {
			int t = num1 + num2;
			num1 = num2;
			num2 = t;
			temp++;
		}
		return num2;
	}

	// 递归的方式完成
	public static int fib2(int n) {
		if (arr[n] != 0) { // 如果数组中保存了数据就返回,没有保存就进入递归
			return arr[n];
		} else {
			if (n <= 0) {
				arr[0] = 0;
				return 0;
			} else if (n == 1) {
				arr[1] = 1;
				return 1;
			} else {
				arr[n] = fib2(n - 1) + fib2(n - 2);
				return arr[n];
			}
		}
	}

}

// 解法3:求出斐波那契数列的通项,即可在O(1)时间复杂度求解
// 线性递推数列的特征方程:x^2 = x + 1,求出x1,x2,则斐波那契数列为f(n) = c1*x1^n+c2*x2^n
// 求出c1,c2即可得到斐波那契数列的通项
public class Main {

	public static void main(String[] args) throws Exception {
		System.out.println(fib(8));
	}

	public static int fib(int n) {
		double result = Math.sqrt(5) / 5 * Math.pow(((1 + Math.sqrt(5)) / 2), n)
				- Math.sqrt(5) * Math.pow(((1 - Math.sqrt(5)) / 2), n); // 斐波那契数列的通项公式
		return (int) Math.round(result);
	}

}

// 解法4:使用矩阵相乘的方式,把问题转化成求矩阵的n-1次幂的第一行第一列的元素,复杂度O(logn)
public class Main {

	public static void main(String[] args) throws Exception {
		System.out.println(fib(6));
	}

	public static int fib(int n) {
		if (n <= 0) {
			return 0;
		} else if (n == 1) {
			return 1;
		} else {
			int[][] arr = { { 1, 1 }, { 1, 0 } };
			return fibHelp(arr, n - 1)[0][0];
		}
	}

	// 与常数的折半乘方一样,只不过现在变成矩阵了
	public static int[][] fibHelp(int[][] arr, int n) {
		if (n == 0) {
			return new int[][] { { 1, 1 }, { 1, 1 } }; // 如果阶乘为0,则返回都是1的矩阵
		}
		if (n == 1) { // 如果阶乘为1,返回原矩阵
			return arr;
		}
		int[][] temp = fibHelp(arr, n / 2);
		int[][] result = new int[2][2];
		result[0][0] = temp[0][0] * temp[0][0] + temp[0][1] * temp[1][0]; // 逐个元素计算,得到两矩阵的相乘结果
		result[0][1] = temp[0][0] * temp[0][1] + temp[0][1] * temp[1][1];
		result[1][0] = temp[1][0] * temp[0][0] + temp[1][1] * temp[1][0];
		result[1][1] = temp[1][0] * temp[0][1] + temp[1][1] * temp[1][1];
		if (n % 2 == 1) { // 如果阶乘为奇数则在乘一个原矩阵
			int[][] temp1 = new int[2][2];
			for (int i = 0; i < 2; i++) {
				for (int j = 0; j < 2; j++) {
					temp1[i][j] = result[i][j];
				}
			}
			result[0][0] = arr[0][0] * temp1[0][0] + arr[0][1] * temp1[1][0];
			result[0][1] = arr[0][0] * temp1[0][1] + arr[0][1] * temp1[1][1];
			result[1][0] = arr[1][0] * temp1[0][0] + arr[1][1] * temp1[1][0];
			result[1][1] = arr[1][0] * temp1[0][1] + arr[1][1] * temp1[1][1];
		}
		return result;
	}

}


解法四的原理


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值