JZ7斐波那契数列
题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。n<=39
示例1
输入
4
返回值
3
方法一:递归(从上向下计算)
题目分析,斐波那契数列公式为:f[n] = f[n-1] + f[n-2],
初始值f[0]=0, f[1]=1,目标求f[n]
看到公式很亲切,代码秒秒钟写完。
int Fibonacci(int n) {
if (n==0 || n==1) return n;
return Fibonacci(n-1) + Fibonacci(n-2);
}
时间复杂度:O(2^n)
空间复杂度:递归栈的空间
优点:
代码简单好写,缺点:
慢,会超时(效率低)
效率低的原因:
方法二:循环(从下向上计算)------------推荐
为了优化
方法一(递归
)中的重复计算,解决办法是按上面树状图从下向上
(循环
)计算
class Solution {
public:
int Fibonacci(int n) {
if(n<=0) return 0;
if(n==1) return 1;
int ret;
int FibN=0;
int FibMinusOne=1;//Minus:减
int FibMinusTwo=0;
for(int i=2;i<=n;i++){
FibN=FibMinusOne+FibMinusTwo;
FibMinusTwo=FibMinusOne;
FibMinusOne=FibN;
}
return FibN;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
JZ8跳台阶
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
示例1
输入
1
返回值
1
示例2
输入
4
返回值
5
题解:
只有1级台阶:f(1)=1;
只有2级台阶:f(2)=2;----------一种跳两次,一次跳1级;一种跳一次,一次跳2级
有n级台阶 :
这就得到了熟悉的公式:
递归
class Solution {
public:
int jumpFloor(int number) {
if(number==1) return 1;
if(number==2) return 2;
return jumpFloor(number-1)+jumpFloor(number-2);
}
};
时间复杂度:O(2^n)
空间复杂度:递归栈的空间
循环-----------推荐(优化)

class Solution {
public:
int jumpFloor(int number) {
if(number==1) return 1;
if(number==2) return 2;
int floorN=0, floorMinusOne=2,floorMinusTwo=1;//注意floorMinusOne,floorMinusTwo的赋值,别赋反了;
for(int i=3;i<=number;i++){
floorN=floorMinusOne+floorMinusTwo;
floorMinusTwo=floorMinusOne;
floorMinusOne=floorN;
}
return floorN;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
JZ9变态跳台阶
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
示例1
输入
3
返回值
4
题解:
设
f[i] 表示 当前跳道第 i 个台阶的方法数。那么f[n]就是所求答案。
跳上n级,有如下情况:
第一步跳1级,还剩n-1级,此时跳法数等于后面n-1级台阶跳法数:f(n-1)
第一步跳2级,还剩n-2级,此时跳法数等于后面n-2级台阶跳法数:f(n-2)
。。。。。。
第一步跳n-1级,还剩1级,此时跳法数等于后面1级台阶跳法数:f(n-(n-1))=f(1)=1
第一步跳n级,还剩0级,此时跳法数等于f(n-n)=f(0)=1
即:
f[n] = f[n-1] + f[n-2] + … + f[0], 初始条件f[0] = f[1] = 1
方法一:暴力方法
根据公式,我们就可以先求f[2],然后f[3]…f[n-1], 最后f[n]
int jumpFloorII(int n) {
if (n==0 || n==1) return 1;
vector<int> f(n+1, 0);// f[i]的初始值为0;
f[0] = f[1] = 1;
for (int i=2; i<=n; ++i) {
for (int j=0; j<i; ++j) {
f[i] += f[j];// f[i]的初始值为0;
}
}
return f[n];
}
时间复杂度:O(n^2)
空间复杂度:O(n),创建了一个 vector<int> f(n+1, 0);
方法二:递推(数学化简)--------推荐
易知 f(n)=f(n-1)+f(n-2)+……f(1)+f(0)
f(n-1)=f(n-2)+……f(1)+f(0)
两式相减得f(n)=2f(n-1)
以n=4为例:
递归实现(从上向下)
class Solution {
public:
int jumpFloorII(int number) {
if(number==0||number==1) return 1;
return 2*jumpFloorII(number-1);
}
};
时间复杂度:O(n)
空间复杂度:递归栈的空间
循环实现(从下向上)---------推荐
class Solution {
public:
int jumpFloorII(int number) {
int n=1;
for(int i=1;i<number;i++){
n=2*n;
}
return n;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
JZ10矩形覆盖
题目描述
我们可以用2*1
的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1
的小矩形无重叠地
覆盖一个2*n
的大矩形,总共有多少种方法?
比如n=3时,2*3的矩形块有3种覆盖方法:
示例1
输入
4
返回值
5
题解参考这里
即,用f [n]表示2*n
大矩阵 的方法数。
显然:
n=1,f(1)=1;
n=2,f(2)=2;
对于2*n
大矩阵,覆盖它的最右面的2*1
小矩阵,要么是竖着的,要么是横着的;
最右边是竖着的需要1个小矩阵(去除这一个竖着的,相当于剩下个2*n-1
大矩阵,此时覆盖方法是f(n-1)
),
横着的需要2个(去除这两个横着的,相当于剩下个2*n-2
大矩阵,此时覆盖方法是f(n-2)
)。
可以得出:
f[n] = f[n-1] + f[n-2],初始条件f[1] = 1, f[2] =2
是斐波那契数列,则用从下向上的循环方式
实现它:
class Solution {
public:
int rectCover(int number) {
if(number<=2) return number;
int f1=1,f2=2;
int fn;
for(int i=3;i<=number;i++){
fn=f1+f2;
f1=f2;
f2=fn;
}
return fn;
}
};
知识点
1.斐波那契数列的题都是从上向下分析,直观上用递归实现,但实际上都会考虑效率问题,采用for循环的形式按从下向上写代码。