小知识,大挑战!本文正在参与「程序员必备小知识」创作活动。
斐波那契数列问题
写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。
递归思路
斐波那契数列为; 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
当我们求数列第n项的值时, 也就是在求第n-1项和第n-2项的和, 也就是f(n) = f(n-1) + f(n-2)
代码 - 递归方式
优点: 代码实现简单易于理解
缺点: 空间复杂度和时间复杂度都很高
public int fibonacciByRecursive(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fibonacciByRecursive(n - 1) + fibonacciByRecursive(n - 2);
}
循环思路
根据f(0)和f(1)解出f(2), 再根据f(1)和f(2)解出f(3), 依此类推, 根据f(n-2)和f(n-1)解出f(n)
代码 - 循环方式
优点: 它的时间复杂度是O(n), 空间复杂度为O(1)
缺点: 它好像没什么缺点
public int fbonacciByCirculation(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
int first = 0;
int second = 1;
int result = 0;
for (int i = 2; i <= n; i++) {
// f(n) = f(n-1) + f(n-2)
result = first + second;
// 更改n-2项的值
first = second;
// 记录n-1项的值
second = result;
}
return result;
}
青蛙上台阶问题
思路
当有1级台阶时, 只有1种跳法
当有2级台阶时, 有2种跳法
当有3级台阶时, 它有可能是从第一级台阶跳过来, 也有可能是从第二级台阶跳过来, 所以是第1级台阶的跳法数目和第二级台阶的跳法数目
当有n级台阶时, 它有可能是从第n-2级台阶跳过来, 也有可能是从第n-1级台阶跳过来, 所以是第n-2级台阶的跳法数目和第n-1级台阶的跳法数目的总和, 即f(n) = f(n-2) + f(n-1)
因此, 该问题是也是一个斐波那契数列问题
代码 - 循环方式
public int numWaysByCirculation(int n) {
if (n == 0 || n == 1) return 1;
if (n == 2) return 2;
int first = 1;
int second = 2;
int result = 0;
for (int i = 3; i <= n; i++) {
result = (first + second) % 1000000007;
first = second;
second = result;
}
return result;
}
代码 - 递归方式
public int numWaysByRecursive(int n) {
if (n == 0 || n == 1) return 1;
if (n == 2) return 2;
return numWaysByRecursive( n - 1) + numWaysByRecursive(n - 2);
}
总结
我们要充分理解递归和循环的思想, 在使用递归的时候, 虽然它的代码很简单, 易于理解, 但是如果数据量大的情况下, 它会有很严重的性能问题, 耗时也会指数增长. 所有的递归解法, 我们都可以转换成循环思想来替代实现. 因此我们要慎用递归, 巧用循环.