爬楼梯问题,每次可以选择爬一阶或者两阶,问总共有多少种方法?
1、一眼望去,直接暴力递归(果然Time Limit Exceeded)
static int cout=0;
public int climbStairs(int n) {
cout=0;
if(n==0)
return 0;
DFS(n, 0);
return cout;
}
public void DFS(int n,int st)
{
if(st>=n)
{
if(st==n)
cout++;
}
if(st+1<=n){
DFS(n,st+1);
}
if(st+2<=n) {
DFS(n,st+2);
}
}
2、在各路大佬的帮助下,发现这是一个Fibonacci 问题,即著名的兔子繁衍问题
最开始有1对兔子,兔子在出生后第3个月起每个月都生一对小兔子,假设兔子不存在死亡的情况,请问10个月后有多少对兔子?
第一个月:1对兔子
第二个月:1对兔子
第三个月:2对兔子(一对老兔子生一对小兔子)
第四个月:3对兔子(一对老兔子又生了一对小兔子)
第五个月:5对兔子(一对老兔子第二次生了一对小兔子,第一次生的一对小兔子也生了一对新兔子)
...
这和爬楼梯问题是十分相似的,直接用递归的方式之所以超时,是因为爬第n阶楼梯的方法数是可以由第n-1阶和第n-2阶推导出来的,所以导致递归很多计算都是重复的
n=1,1
n=2,11,2
n=3,111,21,12
n=4,1111,211,121,112,22
n=5,11111,2111,1211,1121,221,1112,212,122
...
细心的朋友会发现,f(n)=f(n-1)+f(n-2)
如n=4,爬4阶楼梯的情况可以划分为以下两种:
1、爬到3阶楼梯,然后再一口气爬1阶
2、爬到2阶楼梯,然后再一口气爬2阶
知道了方法,现在就是如何求Fibonacci的问题了?
递归大法好,虽然简单,但是还是超时了
public int climbStairs(int n) {
if(n==1)
return 1;
if(n==2)
return 2;
return climbStairs(n-1)+climbStairs(n-2);
}
还是老老实实用循环靠谱,果然0ms,不负众望
public int climbStairs(int n) {
if(n==1)
return 1;
Vector<Integer> st=new Vector<Integer>();
st.add(1);
st.add(1);
for(int i=2;i<=n;i++)
{
st.add(i, st.get(i-1)+st.get(i-2));
}
return st.get(n);
}