斐波那契数列

下面有彩蛋

题目描述

输入一个整数n,求斐波那契数列的第n项。
假定从0开始,第0项为0。(n≤39)(n \leq 39)(n39)

样例
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 &amp; a_{n-1} \end{matrix} \right] , 边界:X_1 = \left[ \begin{matrix} a_1 &amp; a_0 \end{matrix} \right]​Xn=[anan1]X1=[a1a0]

      然后找出变换矩阵:

      A=[1110]A = \left[ \begin{matrix} 1 &amp; 1 \\ 1 &amp; 0 \end{matrix} \right]A=[1110]

      则有:

      Xn=Xn−1×AX_n = X_{n-1} \times AXn=Xn1×A

      矩阵具有结合性,因此:

      Xn=X1×An−1X_n = X_1 \times A^{n-1}Xn=X1×An1

      那么任意求一个斐波那契数列值,主要是求取An−1A^{n-1}An1

    • 实现代码:

      //用于求解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;
}		
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值