题目:我们在上楼梯的时候,假设我们一次上一个台阶,也可以上两个台阶,如果现在有N个台阶,请问它有多少种走法?能帮我实现一个算法吗?
很多同学拿到这道题的时候,想到的是数学问题。不过很多人不小心就陷入了排列组合,在N中求出1与2的组合可能有多少?按照这种思路估计就解不出来这道题了。要理解这道题得从下面两个方面入手:
- 什么叫走法?假设我们现在有3个台阶,它的走法有(1,1,1),(1,2),(2,1),一共三种走法,其实就是X个1和Y个2加起来是N,我们现在去求X个1与Y个2的排列。这里的第一种走法就是每次迈一个台阶对吧?
- 我们走走看,从第一步开始,回顾整个过程。假设有N个台阶,第一步有两种选择,我们假设无论哪种选择,之后都还有台阶
- 第一次上一个,还剩下 N-1个,这时候有多少种走法取决于 N-1个台阶有多少种走法,每种走法的第一步都是1,已经确定了
- 第一次上二个,还剩N-2个,这时候还有多少种走法取决于N-2个台阶有多少种走法,每种走法的第一步都是2,已经确定了
这个时候,大家是不是似乎明白了什么?是不是 当N > 2 时,F(N) = F(N-1) + F(N-2), 而 F(1) = 1, F(2) = 2?
答案就是这么简单,它的递归式就是斐波那契数列对吧。 好的,那我们的编程就很容易实现了。直接上代码哈。
public static int F(int n)
{
if (n > 0 && n <3) return n;
return F(n - 1) + F(n - 2);
}
大家可以自己试一下,按照这种方法求出 F(100)看看要多久?很久很久的!!!!
我们现在对这个算法做一些改良
- 第一步改良, F(n) = F(n-1) + F(n-2), F(n-1) = F(n-2) + F(n-3), 这时候我们发现 F(n-2)算了两次,我们我们需要把它保存下来,减少重复计算。不过这个其实还是递归!
public static int F1(int n)
{
int[] array = new int[n + 1];
if (n < 3 && n > 0) return n;
array[1] = 1;
array[2] = 2;
return FHelper(array, n);
}
private static int FHelper(int[] array, int n)
{
if (n > 0 && n < 3)
{
return n;
}
array[n] = FHelper(array, n - 1) + array[n - 2];
return array[n];
}
- 第二步改良,这样的递归其实可以采取递推的方式来计算的,后面我也打算和大家分享动态规划的内容,到时候可能还会和大家讲这道题。我们可以从1-N的方向解题,每次保存2个数, F(1), F(2), 我们就能求出F(3)了。我们再一起看代码
public static int F2(int n)
{
if (n > 0 && n < 3)
return n;
else if (n >= 3)
{
int first = 1, second = 2;
int third = 0;
for (int i = 3; i <= n; i++)
{
third = first + second;
first = second;
second = third;
}
return third;
}
throw new ArgumentException("N 应该大于0");
}
第二种改良方法中已经没有递归了,不过它有更加容易理解的方式去写。之后我会给大家介绍这种递归改良的套路。
还没有结束哈。大家再想一想,如果这种人足够强壮,他每次抬脚,可以走一步,两步,或者三步,那大家能自己写出来一共有多少种走法呢?
好了,我们这道题就先聊到这哈。感兴趣的同学可以加我们的QQ群参与讨论,微信公众号获取更多资讯。还欢迎大家访问我的视频教程,了解更多经典面试题。