负一、我的想法
昨天晚上睡前看了一下问题描述,讲的是一只青蛙跳n个台阶,一次可以跳一阶,一次也可以跳两阶,问一共有多少种跳法。
当时我的思路是:
先想了n=1和n=2的情况,
当n=1时,只有一种跳法--即1;
当n=2时,有两种跳--1 1或者2
因为小青蛙一次可以跳1或者2,
所以我想把n=1和n=2的情况作为递归出口。
比如,n=3的情况,就相当于小青蛙跳了一个2,和一个1
并且他们之间是可以有顺序的,
一共两种顺序:
小青蛙先跳一个n=1,再跳一个n=2;
小青蛙先跳一个n=2,再跳一个n=1。
然而,问题出现了,当小青蛙跳n=2时,选择了1 1跳法,
那么此时上述两种顺序跳出来的结果都是1 1 1,
说明有重复。
当n取更大的时候,这种重复更多,我们需要把它减去。
想到这的时候,我就知道,我的想法肯定错了。
递归算法是为了让人好理解,牺牲一部分机器的运行时间,来换取程序的更强可读性。
我这想法已经把自己绕进去了,显然是不可行的。
下面一起来学一学这个问题吧!
【一、思路 中会阐述清楚为什么不会出现重复问题】
零、问题描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多少种跳法?
一、思路
当n=1时,一共有一种跳法(1)
当n=2时,一共有两种跳法(1,1),(2)
当n>2时,
这里我们以n=3为例:
由于很好枚举,我们直接给出跳法,
一共3种:
(1,1,1)
(1,2)
(2,1)
如果我们去掉跳的第一次,
如(1,1,1)一共跳了3次,去掉第一次跳的1阶,剩下的结果为(1,1)
同理,剩下两种跳法去掉第一次后的结果分别为(2)和(1)。
我们把他们放在一起看一下:
(1,1)
(2)
(1)
再观察:这前两种:(1,1)和(2)不正好是n=2时的跳法吗?
最后一种,也正好是n=1的跳法。
我们再来枚举一下n=4的情况:
(1,1,1,1)
(1,1,2)
(1,2,1)
(2,1,1)
(2,2)
一共五种。
以第一步跳的是1还是2,我们来划上分割线:
(1,1,1,1)
(1,1,2)
(1,2,1)
------分割线-----------上为A段,下为B段
(2,1,1)
(2,2)
然后,我们对A段进行去掉第一步的处理:
(1,1,1)
(1,2)
(2,1)
是n=3的情景。
同理,对B段进行去掉第一步的处理:
(1,1)
(2)
是n=2的情景。
这时候,递归出来了:
n=4可以划分为n=3和n=2两个子问题,而n=3又可以划分为n=2和n=1两个子问题,
也就是说,n=4 --> n=3 + n=2 --> n=2 + n=1 + n=2
而n=1和n=2就是我们的初始条件,递归出口,
所以完成了递归。
函数递推式:
本题和斐波那契数列有异曲同工之妙。
回过头来,我们再想想一开始我的想法出现的问题:是否会导致重复?
答案是不会的。
因为我们是以第一步是1还是2来划分子问题,这里的2是一次跳两阶,很明显,第一步已经不一样了,所以不会出现重复的问题。
用概率论的思想就是先分类
分第一步跳1次还是2次两大类
分类用加法;
而对于第一步跳一次的情景,
它又和后面的步骤形成了分步执行问题
分步用乘法。
但是它自身就只有一步,
所以相当于是
f(n) = 1*f(n-1) + 1*f(n-2)。
这里我们就把是否会出现重复问题给讲清楚了。
二、代码实现
int frog_jump(int n)
{
if (n == 1)
return 1;
else if (n == 2)
return 2;
else
return frog_jump(n - 1) + frog_jump(n - 2);
}
int main()
{
cout << frog_jump(5);
return 0;
}
本样例代码程序执行结果为8,
测试多组样例,满足题意。