斐波那契数列(C++ 和 Python 实现)
(说明:本博客中的题目、题目详细说明及参考代码均摘自 “何海涛《剑指Offer:名企面试官精讲典型编程题》2012年”)
题目
1. 写一个函数,输入 n, 求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:

2. 一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个n级的台阶总共有多少种跳法?
3. 一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级,...... ,也可以跳上n级,此时该青蛙跳上一个 n 级的台阶共有多少种跳法?
4. 用 2x1 (图 2.13 的左边)的小矩形横着或者竖着去覆盖更大的矩形。请问用 8 个 2x1 小矩形无重叠地覆盖一个 2x8 的大矩形(图 2.13 的右边),总共有多少种方法?

题目解析
本博客提及到 4 个题目:题目 1 直接给出斐波那契数列的定义,可采用多种算法实现,这些算法思想将在 “算法设计思想“ 部分介绍;题目 2 和题目 4 的本质上解决的还是斐波那契数列第 n 项的计算问题,即题目 1;题目 3 可以说是数学问题,只要意识到其计算的实质上是 2 的 n 次幂即可,剩下的工作采用程序就很容易实现了。
下面具体说如何理解题目 2、题目 3 和 题目4:
- 对于题目 2,青蛙每次只能跳上 1 级或 2 级台阶。假定青蛙需要跳上 n 级台阶,其可能的组合数为 g(n) 。青蛙第 1 次跳台阶有 2 种可能:跳上 1 级台阶,剩余 n-1 级台阶;跳上 2 级台阶,剩余 n-2 级台阶。所以 g(n) = g(n-1) + g(n-2),即青蛙跳上 n 级台阶的可能的组合数等于第 1 次跳上 1 级台阶的可能组合数加上第 1 次跳上 2 级台阶的可能组合数。也可理解为以何种方式跳上第 n 级台阶(跳上 1 级台阶,还是跳上 2 级台阶)。至此,就转化为求解斐波那契数列的第 n 项问题。
- 对于题目 3,与题目 2 相比,区别在于青蛙每次可以跳上任意级台阶,不仅仅是 1 级或 2 级台阶。如果此时青蛙需要跳上 n 级台阶,可采取的跳法有 f(n) = 2n-1 种。可以采用数学归纳法证明,具体证明思路如下:
当 n = 1或 n = 2 时, 显然成立;
令 n = k 时, f(k) = 2k-1 成立,当 n = k+1 时,f(k+1) = f(k) + f(k-1) + f(k-2) + ... + f(1) + 1. 在增加 1 级台阶后,可以理解为,设青蛙在跳上最后一级台阶(新增加的台阶)时,所跳上的台阶数为 x,若 x = 1,则此时可采跳法是 f(k) 种跳法;若 x = 2,则此时可采取的跳法为 f(k-1); 如此下去,一直到 x = k-1 时,则此时可采取的跳法为 f(1);除此之外,还需要加上一种 x = k+1 可能,即只需一次直接跳上 k+1 级台阶。又因为

- 对于题目 4,使用图 2.13 左图 (2x1的矩形,也可变换为1x2矩形,设为形状A) 填充图 2.13 的右图 (2x8的矩形,设为形状B(8),其中8为列数) 时,如果先放置一块,有两种放法,一种横着放,一种是竖着放。如果第一次横着放,则下一个也必须是横着放,此时问题变为使用形状 A 填充形状 B(6);如果第一次是竖着放,则问题变为使用形状 A 填充形状 B(7)。为了表示方便,则依旧用相同的符号 B 表示为用 A 填充 B 的方法数,则有 B(8) = B(6) + B(7),从递推公式可以看出,这是一个斐波那契数列的问题。
算法设计思想
1. 递归方法(Recursive Method)。循环调用自身。缺点:有大量的重复计算,不实用。优点:实现非常简单,代码短小。对于斐波那契数列的实现,其时间复杂度为 O(2n)。
2. 迭代方法 (Iterative Method)。通过循环,替代递归方法,从理论上说,任何递归算法都可用迭代算法实现。优点:节省栈空间,有可能降低时间复杂度。缺点是相对于递归方法,实现较难,代码往往会复杂一些。对斐波那契数列,其时间复杂度为 O(n),是比较实用的算法。
3. 公式法。通过不常用的计算斐波那契数列的第 n 项的数学公式,如果采用合适的实现方式,可将时间复杂度降为 O(logn),具体数学公式和相关说明如下(摘自参考资料):

C++ 实现
#include <iostream> // Method 1: recursive method and its time complexity is O(2^n).
int fibonacciRecursively(int n)
{
int result; if (n <= )
result = ;
else if ( == n)
result = ;
else
result = fibonacciRecursively(n-) + fibonacciRecursively(n-); return result;
} // Method 2: iterative method and its time complexity is O(n).
int fibonacciIteratively(int n)
{
int result = ;
int nextItem = ; for (int i = ; i <= n; ++i)
{
int tmp = nextItem;
nextItem += result;
result = tmp;
} return result;
} // Method 3: by means of the specified matrix power
long int* matrixPower(long int *mat, int n); // compute the power of the matrix int fibonacciMatrixPower(int n)
{
long int matrix[] = {, , , };
int result = ;
if (n <= )
result = ;
else
{
matrixPower(matrix, n-);
result = matrix[];
} return result;
} // 2 x 2 matrix power, n >= 0
long int* matrixPower(long int *mat, int n)
{
const int rows = ;
const int cols = ; if (n <= )
return NULL;
else if ( == n)
{
// identity matrix when the power of a matrix is 0.
for (int i = ; i < rows; ++i)
for (int j = ; i < cols; ++j)
{
if (i == j)
*(mat + i * cols + j) = ;
else
*(mat + i * cols + j) = ;
}
}
else if ( == n)
{
}
else if ( == n)
{
// Create two temporary arrays for matrix multiplication
long int tmpMat1[], tmpMat2[];
for (int i = ; i < rows; ++i)
for (int j = ; j < cols; ++j)
{
tmpMat1[i*cols+j] = *(mat + i * cols + j);
tmpMat2[i*cols+j] = *(mat + i * cols + j);
}
// matrix multiplication
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+]; // matrix{0,0}
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+]; // matrix{0,1}
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+]; // matrix{1,0}
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+]; // matrix{1,1}
}
else if (n % == ) // when n is even and n is greater than 2
{
matrixPower(mat, n/);
matrixPower(mat, );
}
else // n is odd and n is greater than 2
{
long int tmpMat1[];
for (int k = ; k < ; ++k)
tmpMat1[k] = *(mat + k);
// Compute matrix power in even case
matrixPower(mat, n-);
// Temporarily save the matrix
long int tmpMat2[];
for (int k = ; k < ; ++k)
tmpMat2[k] = *(mat + k);
// matrix multiplication with additional element.
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+];
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+];
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+];
*(mat + * cols + ) = tmpMat1[*cols+] * tmpMat2[*cols+] + tmpMat1[*cols+] * tmpMat2[*cols+];
} return mat;
} void unitest()
{
int n = ;
std::cout << "The " << n << "-th item in the fibonacci sequence: \n"
<< " Recursive method result: " << fibonacciRecursively(n) << std::endl
<< " Iterative method result: " << fibonacciIteratively(n) << std::endl
<< " Matrix power method result: " << fibonacciMatrixPower(n) << std::endl
;
} int main()
{
unitest(); return ;
}
Python 实现
#!/usr/bin/python
# -*- coding: utf8 -*- # Method 1: recursive method
def fib_recursively(n):
result = 0 if n >= 1:
if 1 == n:
result = 1
else:
result = fib_recursively(n-1) + fib_recursively(n-2) return result # Method 2: iterative method
def fib_iteratively(n):
result, next_item = 0, 1
i = 1
while i <= n:
result, next_item = next_item, result + next_item
i += 1 return result # Method 3: matrix power
def fib_matrix_power(n):
matrix = [1, 1, 1, 0]
result = 0
if n > 0:
matrix_power(matrix, n-1)
result = matrix[0] return result # 2 x 2 matrix power
def matrix_power(mat, n):
rows, cols = 2, 2 # 2 x 2 matrix if n <= 0:
return None
elif 0 == n:
mat[:] = [1, 0, 0, 1] # identity matrix
elif 1 == n:
pass
elif 2 == n:
tmp_mat1, tmp_mat2 = [], []
tmp_mat1.extend(mat)
tmp_mat2.extend(mat)
# matrix multiplication
for i in range(rows):
for j in range(cols):
mat[i*cols+j] = inner_product(tmp_mat1[i::cols], tmp_mat2[j::cols])
elif n % 2 == 0: # even case
matrix_power(mat, n/2)
matrix_power(mat, 2)
else:
# temporarily save mat
tmp_mat1 = []
tmp_mat1.extend(mat)
# recursive call
matrix_power(mat, n-1)
# multiply with former temporary value
tmp_mat2 = []
tmp_mat2.extend(mat)
for i in range(rows):
for j in range(cols):
mat[i*cols+j] = inner_product(tmp_mat1[i::cols], tmp_mat2[j::cols]) return mat def inner_product(vec1, vec2):
product = 0
if (vec1 and vec2 and len(vec1) == len(vec2)):
for i in range(len(vec1)):
product += vec1[i] * vec2[i]
return product if __name__ == '__main__':
n = 5
print("The %d-th item in the fibonacci sequence:" % n)
print(" Recursive method result: %d" % fib_recursively(n))
print(" Iterative method result: %d" % fib_iteratively(n))
print(" Matrix power method result: %d" % fib_matrix_power(n))
参考代码
1. targetver.h
#pragma once // The following macros define the minimum required platform. The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified. // Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
2. stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
// #pragma once #include "targetver.h" #include <stdio.h>
#include <tchar.h> // TODO: reference additional headers your program requires here
3. stdafx.cpp
// stdafx.cpp : source file that includes just the standard includes
// Fibonacci.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H
// and not in this file
4. Fibonacci.cpp
// Fibonacci.cpp : Defines the entry point for the console application.
// // 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛 #include "stdafx.h" // ====================方法1:递归====================
long long Fibonacci_Solution1(unsigned int n)
{
if(n <= )
return ; if(n == )
return ; return Fibonacci_Solution1(n - ) + Fibonacci_Solution1(n - );
} // ====================方法2:循环====================
long long Fibonacci_Solution2(unsigned n)
{
int result[] = {, };
if(n < )
return result[n]; long long fibNMinusOne = ;
long long fibNMinusTwo = ;
long long fibN = ;
for(unsigned int i = ; i <= n; ++ i)
{
fibN = fibNMinusOne + fibNMinusTwo; fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
} return fibN;
} // ====================方法3:基于矩阵乘法====================
#include <cassert> struct Matrix2By2
{
Matrix2By2
(
long long m00 = ,
long long m01 = ,
long long m10 = ,
long long m11 =
)
:m_00(m00), m_01(m01), m_10(m10), m_11(m11)
{
} long long m_00;
long long m_01;
long long m_10;
long long m_11;
}; Matrix2By2 MatrixMultiply
(
const Matrix2By2& matrix1,
const Matrix2By2& matrix2
)
{
return Matrix2By2(
matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10,
matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11,
matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10,
matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11);
} Matrix2By2 MatrixPower(unsigned int n)
{
assert(n > ); Matrix2By2 matrix;
if(n == )
{
matrix = Matrix2By2(, , , );
}
else if(n % == )
{
matrix = MatrixPower(n / );
matrix = MatrixMultiply(matrix, matrix);
}
else if(n % == )
{
matrix = MatrixPower((n - ) / );
matrix = MatrixMultiply(matrix, matrix);
matrix = MatrixMultiply(matrix, Matrix2By2(, , , ));
} return matrix;
} long long Fibonacci_Solution3(unsigned int n)
{
int result[] = {, };
if(n < )
return result[n]; Matrix2By2 PowerNMinus2 = MatrixPower(n - );
return PowerNMinus2.m_00;
} // ====================测试代码====================
void Test(int n, int expected)
{
if(Fibonacci_Solution1(n) == expected)
printf("Test for %d in solution1 passed.\n", n);
else
printf("Test for %d in solution1 failed.\n", n); if(Fibonacci_Solution2(n) == expected)
printf("Test for %d in solution2 passed.\n", n);
else
printf("Test for %d in solution2 failed.\n", n); if(Fibonacci_Solution3(n) == expected)
printf("Test for %d in solution3 passed.\n", n);
else
printf("Test for %d in solution3 failed.\n", n);
} int _tmain(int argc, _TCHAR* argv[])
{
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, ); Test(, ); return ;
}
5. 参考代码下载
项目 09_Fibonacci 下载: 百度网盘
何海涛《剑指Offer:名企面试官精讲典型编程题》 所有参考代码下载:百度网盘
参考资料
[1] 何海涛. 剑指 Offer:名企面试官精讲典型编程题 [M]. 北京:电子工业出版社,2012. 71-77.
斐波那契数列(C++ 和 Python 实现)的更多相关文章
- 斐波拉契数列(Fibonacci) 的python实现方式
第一种:利用for循环 利用for循环时,不涉及到函数,但是这种方法对我种小小白来说比较好理解,一涉及到函数就比较抽象了... >>> fibs = [0,1] >>&g ...
- Python递归及斐波那契数列
递归函数 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数.举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示,可 ...
- python实现斐波那契数列(Fibonacci sequence)
使用Python实现斐波那契数列(Fibonacci sequence) 斐波那契数列形如 1,1,2,3,5,8,13,等等.也就是说,下一个值是序列中前两个值之和.写一个函数,给定N,返回第N个斐 ...
- Python 实现 动态规划 /斐波那契数列
1.斐波那契数列 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数 ...
- Python中斐波那契数列的赋值逻辑
斐波那契数列 斐波那契数列又称费氏数列,是数学家Leonardoda Fibonacci发现的.指的是0.1.1.2.3.5.8.13.21.34.······这样的数列.即从0和1开始,第n项等于第 ...
- 用递归方法计算斐波那契数列(Recursion Fibonacci Sequence Python)
先科普一下什么叫斐波那契数列,以下内容摘自百度百科: 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因意大利数学家列昂纳多·斐波那契(Leonardoda Fibonacci ...
- python实现斐波那契数列
https://www.cnblogs.com/wolfshining/p/7662453.html 斐波那契数列即著名的兔子数列:1.1.2.3.5.8.13.21.34.…… 数列特点:该数列从第 ...
- python学习笔记之斐波拉契数列学习
著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... 如果用Python的列表生成式, ...
- Python编程笔记(第三篇)【补充】三元运算、文件处理、检测文件编码、递归、斐波那契数列、名称空间、作用域、生成器
一.三元运算 三元运算又称三目运算,是对简单的条件语句的简写,如: 简单条件处理: if 条件成立: val = 1 else: val = 2 改成三元运算 val = 1 if 条件成立 else ...
- Python中斐波那契数列的四种写法
在这些时候,我可以附和着笑,项目经理是决不责备的.而且项目经理见了孔乙己,也每每这样问他,引人发笑.孔乙己自己知道不能和他们谈天,便只好向新人说话.有一回对我说道,“你学过数据结构吗?”我略略点一点头 ...
随机推荐
- Linux 开机、重启和用户登录注销、用户管理、用户组
l 关机&重启命令 基本介绍: shutdown –h now 立该进行关机 shudown -h 1 "hello, 1 分钟后会关机了" shutdown –r n ...
- Caused by java.lang.IllegalStateException Not allowed to start service Intent { cmp=com.x.x.x/.x.x.xService }: app is in background uid UidRecord问题原因分析(二)
应用在适配Android 8.0以上系统时,会发现后台启动不了服务,会报出如下异常,并强退: Fatal Exception: java.lang.IllegalStateException Not ...
- 在ionic3+angular4项目中添加自定义图标
在阿里图标库下载自己所需要的图标解压为一下目录 把iconfont.xx文件全部放到src/assets/fonts/文件夹下,可以全部替换里面的文件,但是要把之前iconfont.css文件下的文件 ...
- ScriptManager.RegisterStartupScript失效的解决方案
在项目中一个页面使用System.Web.UI.ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "success ...
- 常用linux网络工具
iftop netstat nethogs可以查看进程占用网络的情况 nc -u -z -w2 192.168.0.1 1-1000 //扫描192.168.0.3 的端口 范围是 1-1000
- OpenCV文本图像的旋转矫正
用户在使用Android手机拍摄过程中难免会出现文本图像存在旋转角度.这里采用霍夫变换.边缘检测等数字图像处理算法检测图像的旋转角度,并根据计算结果对输入图像进行旋转矫正. 首先定义一个结构元素,再通 ...
- MySQL触发器基本介绍
基本简介: 1.触发器可以让你在执行insert,update,delete语句的时候,执行一些特定的操作.并且可以在MySQL中指定是在sql语句执行前触发还是执行后触发. 2.触发器没有返回值. ...
- [转]Work With Odata in Web API: Create Your First Odata Service
本文转自:http://www.c-sharpcorner.com/UploadFile/dacca2/work-with-odata-in-web-api-create-your-first-oda ...
- [android] 通过比对进行容器联动
当中间容器变化之后,标题栏也要跟着变化 设计个比对依据: 抽象类BaseView中定义抽象方法,每个继承的View都必须实现,为自己的界面定义一个唯一的int常量,作为比对依据 降低容器之间的耦合度: ...
- java 的底层通信--Socket
以前一直不太重视java 基础的整理,感觉在实际开发中好像java 基础用处不大,感觉不理解一些底层的东西对开发工作影响也不大.不过,后来我发现,很多东西都是相互联系的,如果底层的东西你不理解,后面的 ...