下面有彩蛋
题目描述
输入一个整数n,求斐波那契数列的第n项。
假定从0开始,第0项为0。(n≤39)(n \leq 39)(n≤39)
样例
Input: n = 5
Output: 5
解题思路
-
普通思路
-
描述
使用递推+滚动变量的做法。
-
实现代码:
int F(int n) { int tmp1 = 0, tmp2 = 1; // while循环条件比较巧妙,这样整个循环可以处理任意数的斐波那契数列值 while (n--) { // 递推赋值 tmp2 = tmp1 + tmp2; tmp1 = tmp2 - tmp1; } return tmp1; }
-
复杂度分析
时间复杂度:O(n)O(n)O(n)
while循环n次
空间复杂度: O(2)≈O(1)O(2) \approx O(1)O(2)≈O(1)
使用两个临时变量tmp1和tmp2
-
-
中级思路
-
描述
使用递归的做法。
-
实现代码
int F(int n) { if (n <= 0) { return 0; } if (n == 1) { return 1; } return F(n - 1) + F(n - 2); }
-
复杂度分析
时间复杂度:O(n2)O(n^2)O(n2)
画出递归树,可知树深度为n,并且每一个节点含有两个子节点
空间复杂度:O(0)O(0)O(0)
没有使用辅助变量
-
-
高级思路
-
描述
使用矩阵运算 + 快速幂乘的做法。
首先我们定义向量:Xn=[anan−1],边界:X1=[a1a0]X_n = \left[ \begin{matrix} a_n & a_{n-1} \end{matrix} \right] , 边界:X_1 = \left[ \begin{matrix} a_1 & a_0 \end{matrix} \right]Xn=[anan−1],边界:X1=[a1a0]
然后找出变换矩阵:
A=[1110]A = \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right]A=[1110]
则有:
Xn=Xn−1×AX_n = X_{n-1} \times AXn=Xn−1×A
矩阵具有结合性,因此:
Xn=X1×An−1X_n = X_1 \times A^{n-1}Xn=X1×An−1
那么任意求一个斐波那契数列值,主要是求取An−1A^{n-1}An−1。
-
实现代码:
//用于求解A * B = C void mulMatrix(int a[][2], int b[][2], int c[][2]) { int tmp[][2] = { {0,0},{0,0} }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { tmp[i][j] += a[i][k] * b[k][j]; } } } for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { c[i][j] = tmp[i][j]; } } } int F(int n) { int x[2] = { 1,0 }; //边界值[1,1] int a[2][2] = { {1,1},{1,0} }; //存储A int res[][2] = { { 1,0 },{ 0,1 } }; //存储单位矩阵E int t[2][2] = { { 1,1 },{ 1,0 } }; //主要用于表示 int k = n - 1; //表示乘方次数 //该循环获取A^(n-1) while (k) { if (k&1) //表明k%2 == 1 { mulMatrix(res, t, res); } mulMatrix(t, t, t); k >>= 1; } return res[0][0] + res[0][1]; }
-
复杂度分析
时间复杂度:O(logn)O(log^n)O(logn)
快速幂乘需要lognlog^nlogn
空间复杂度:≈O(1)\approx O(1)≈O(1)
使用有限个数组
-
快速幂乘
原理(k 使用二进制表示,一定可以表示为 2i+……+2k2^i + …… + 2^k2i+……+2k):
xk=x2i+……+2k=x2i×……×x2kx^k = x^{2^i + …… + 2^k} = x^ {2^i} \times ……\times x^{2^k}xk=x2i+……+2k=x2i×……×x2k
使用一个变量存储x2ix^ {2^i}x2i,另一个变量存储返回结果即可。
//求m^k % p
int quickMul(int m, int k, int p)
{
int res = 1, t = m; // res存储结果,t存储x^i
while (k)
{
if (k&1)
{
res = res * t % p;
}
t = t * t % p;
k >>= 1;
}
return res;
}