转载本文章请标明作者和出处
本文出自《Darwin的程序空间》
本文题目和部分解题思路来源自《剑指offer》第二版
题目
求斐波那契数列的第n项。
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0;F(1) = 1;F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
解题分析与代码
这道题可能大学学过计算机的首先都会想到递归算法,求第n个数,那么就可以递归去求n-1和n-2那么就知道了n的答案,具体代码如下。
- 方式1 | 递归解法(不可取)
public class Offer10_Fib {
public static void main(String[] args) {
System.out.println(fib(6));
}
public static int fib(int n) {
if (n < 1) {
return 0;
}
if (n == 1) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
}
这种方式的好处就是代码比较简洁,明了,但是效率并不高,因为重复计算了太多的值,如果要计算n=5的值,那么我们的调用数如下:
我们可以看到即使n=5,n=1都被计算了5次,那么想想看如果n=100,那么这个算法会有多慢。所以在面试的过程中,这种方式捎带提过就好,不能作为给面试官的标准输出答案。
- 方式2 | 动态规划(通用,一般是面试官想看到的解法)
就是我们已经计算出来的值,就要利用到,不再去计算第二遍;
你品,你细品,你仔细品,是不是在点方法1是个**,,咳咳~~~
我们首先定义长度为2的一个数组arr,来记录F(n)的值,首先arr[0]对应的是0(F(0) = 0)、arr[1]对应的是1(F(1) = 1);
然后当要计算n=2的时候,我们把arr[1]复制到arr[0]的位置,然后arr[1]等于原来的arr[1]+arr[0],这就相当于我们保存了n=1和n=2的值,如果我们所求为n=5,那么我们就重复以上操作,指导arr[1]记录的是n=5的值即可。
这种解法只需要遍历一遍即可,时间复杂度为O(n),空间复杂度为O(1),因为我们只定义了常数个变量。
public class Offer10_Fib {
public static void main(String[] args) {
System.out.println(fib(6));
}
public static int fib(int n) {
int[] arr = new int[2];
arr[1] = 1;
if (n < 2) {
return arr[n];
}
int temp;
for (int i = 2; i <= n; i++) {
temp = arr[1];
arr[1] = arr[0] + arr[1];
arr[0] = temp;
}
return arr[1];
}
}
- 方式3 | 线性代数(可以向面试官展示自己的知识面,不通用)
这个解法需要一点线性代数的基础,碰巧笔者大学线性代数考了96,(我同桌抄我的考了95…),于是看到何海涛(剑指offer作者)提出这种解法的时候,下床三下五除二就实现了,但是面试官一般不是真的考你这种算法,毕竟我们不是学数学的,所以知道的能用上就装个*,不知道的了解一下即可。
class Solution {
public int fib(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
int[][] matrix1 = new int[][]{new int[]{0, 1}, new int[]{0, 0}};
int[][] matrix2 = new int[][]{new int[]{0, 1}, new int[]{1, 1}};
for (int i = 1; i < n; i++) {
matrix1 = matrixMultiplication(matrix1, matrix2);
}
return matrix1[0][1];
}
/* 矩阵相乘计算 */
private int[][] matrixMultiplication(int[][] matrix1, int[][] matrix2) {
if (matrix1.length != matrix2[0].length) {
return null;
}
int[][] result = new int[matrix1.length][matrix2[0].length];
for (int i = 0; i < matrix1.length; i++) {
for (int j = 0; j < matrix2[0].length; j++) {
for (int k = 0; k < matrix2.length; k++) {
result[i][j] += matrix1[i][k] * matrix2[k][j];
}
}
}
return result;
}
}
拓展
和本题高度类似的有爬楼梯问题,leetcode上搜索爬楼梯即可,我这里给出我的答案,请同学们参考。
class Solution {
public int climbStairs(int n) {
if (n <= 0) {
return 0;
} else if (n == 1) {
return 1;
} else if (n == 2) {
return 2;
}
int[] result = new int[2];
result[0] = 1;
result[1] = 2;
for (int i = 2; i < n; i++) {
int temp = result[1];
result[1] = result[0] + result[1];
result[0] = temp;
}
return result[1];
}
}