题目一:求斐波那契数列顶的第n项
写一个函数,输入n,求斐波那契数列的第n项。Fibonacci数列的定义如下:
n=0,f(n)=0 n=1,f(n)=1, if n>1;f(n)=f(n-1)+f(n-2)
思路:
这个问题是比较常见的问题,用递归的方法我们可以很快的写出代码:
#include <iostream>、
using namespace std;
long long Fibonacci(unsigned int n)
{
if (n <= 0)
return 0;
if (n == 1)
return 1;
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
但是这个方法在效率上会有严重的问题,每次计算一个数都需要重复计算之前已经计算过的数,这是一种重复度非常大的计算方法。这里我们可以引入动态规划的思想,将计算好的前面的数据直接利用到后面的计算中去,比如用递推的方法,从第一项开始往后进行计算,这样每个数据只需要计算依次就可以求出最后的结果。或者用空间换取时间,用一个数组来储存计算过的值,当需要这个值的时候直接调用即可。
//从下到上进行递推
long long Fibonacci(unsigned n)
{
int result[2] = { 0,1 };
if (n < 2)
return result[n];
long long fibNMinusOne = 0;
long long fibNMinusTwo = 1;
long long fibN = 0;
for (unsigned int i = 2; i <= n; i++)
{
fibN = fibNMinusOne + fibNMinusTwo;
fibNMinusOne = fibNMinusTwo;
fibNMinusTwo = fibN;
}
return fibN;
}
//开一个数组来记录之前计算过的值
#include <iostream>
#include<cstring>
using namespace std;
const int maxn = 1000;
int dp[maxn];
int F(int n)
{
if (n == 0) return 0;
if (n == 1) return 1;
if (dp[n] != -1) return dp[n];
else
{
dp[n] = F(n - 1) + F(n - 2);
return dp[n];
}
}
int main()
{
memset(dp, -1, sizeof(dp));
}
题目二:青蛙跳台阶问题
1. 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法。
边界情况,如果n=1,那么只有一种跳法,n=2,有两种跳法。推广开来,当n>2时,第一次跳有两种选择,一是第一次跳1级,此时跳法的数目为后面剩下的n-1级台阶的跳法数目,即为f(n-1)。二是第一次跳2级,此时跳法的数目为后面剩下的n-2级台阶的跳法数目,即f(n-2)。那么就有f(n)=f(n-1)+f(n-2)。得到一个递推关系,我们惊讶的发现,这就是一个Fibonacci数列,前两项为1和2,后面每一项等于前两项的和。
2. 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(n-(n-1)) + f(n-n)= f(0) + f(1) + f(2) + f(3) + ... + f(n-2)+f(n-1)
f(n-1) = f(0) + f(1)+f(2)+f(3) + ... + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2)
so f(n)=2*f(n-1)
public int Jump3(int n) {
if (n <= 1) {
return 1;
} else {
return 2 * Jump3(n - 1);
}
}
也就是会有种跳法。
4. 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个m级的台阶总共有多少种跳法。
先列多项式(假设m>n):
f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(m-n)
f(n-1) = f(n-2) + f(n-3) + ... + f(m-n) + f(m-n-1)
化简得:f(n) = 2f(n-1) - f(m-n-1)
复习:
求斐波拉契数列的递归写法会有很多重复计算,效率比较低,但是如果一定要用递归可以采用动态规划的方法,每次计算一个值就将其存到数组里面,这样下次需要这个值的时候就不需要再进行计算了。当然,最好还是用子夏而上的循环来进行计算,这样不需要借助辅助数组了。青蛙跳台阶的问题也要知道推导的方法。
二刷代码:
long long Finonacci(unsigned int n)
{
int result[2] = { 0,1 };
if (n < 2)
return result[n];
long long FinonacciOne = 1;
long long FinonacciTwo = 0;
long long FiN = 0;
for (unsigned i = 2; i <= n; ++i)
{
FiN = FinonacciOne + FinonacciTwo;
FinonacciTwo = FinonacciOne;
FinonacciOne = FiN;
}
return FiN;
}