1. 题目来源
链接:用两个栈实现队列
来源:LeetCode——《剑指-Offer》专项
2. 题目说明
写一个函数,输入 n
,求斐波那契(Fibonacci
)数列的第 n
项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 :
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
提示:
- 0 <= n <= 100
3. 题目解析
3.1 方法一:自下而上、循环求解
做好 %
的运算就行了,否则会爆掉
// 执行用时 :8 ms, 在所有 C++ 提交中击败了61.41%的用户
// 内存消耗 :8 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
int fib(int n) {
long long a = 0, b = 1, c = 0;
if (n == 0)
return 0;
if (n == 1)
return 1;
while (--n) {
c = a % 1000000007 + b % 1000000007;
a = b;
b = c;
}
return c % 1000000007;
}
};
3.2 青蛙跳台阶、经典递归
把 n
级台阶时的跳法看成是 n
的函数,记为 f(n)
。当 n>2
时,第一次跳的时候就有两种不同的选择
- 一是第一次只跳 1 级,此时跳法数目等于后面剩下的
n-1
级台阶的跳法数目,即为f(n-1)
- 另外一种选择是第一次跳 2 级,此时跳法数目等于后面剩下的
n-2
级台阶的跳法数目,即为f(n-2)
因此n级台阶的不同跳法的总数 f(n)=f(n-1)+f(n- 2)
。
// 执行用时 :4 ms, 在所有 C++ 提交中击败了61.72%的用户
// 内存消耗 :8.2 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
int numWays(int n) {
long long arr[2] = {1, 1};
if (n < 2)
return arr[n];
long long a = 1, b = 1, c = 0;
while (--n) {
c = a % 1000000007 + b % 1000000007;
a = b;
b = c;
}
return c % 1000000007;
}
};
3.3 fib数列 计算法
以前做题遇到过,没深究,再次遇到了,总结一下:
算法:由于这种算法需要用到一个很生僻的数学公式,因此很少有面试官会要求我们掌握。不过以防不时之需,我们还是简要介绍一下这种算法。在介绍这种方法之前,我们先介绍一个数学公式:
这个公式用数学归纳法不难证明,在此不作证明
了这个公式,我们只需要求得矩阵
即可得到 f(n)
。现在的问题转为如何求矩阵的乘方。如果只是简单地从 0 开始循环,n
次方需要 n
次运算,那其时间复杂度仍然是
,并不比前面的方法快。但我们可以考虑乘方
的如下性质:
从上面的公式我们可以看出,想求得 n
次方,就要先求得n/2
次方,再把 n/2
次方的结果平方一下即可。这可以用递归的思路实现。可以脑补递归树。
3.4 斐波拉契数列通项公式与求和公式
这个数列从第三项开始,每一项都等于前两项之和。它的通项公式为:
又叫 “比内公式”,是用无理数表示有理数的一个范例。当 n
趋于无穷大时,前后两项比约等于黄金比率。
斐波那契数列求和公式:
文字说明:数列的最后一项的两倍加上倒数第二项再减去1
证明过程简单贴在下面: