题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解法1
本题是【剑指Offer】跳台阶的进化版本。
原来的青蛙只可以跳上1级或2级,即F(n) = F(n - 1) + F(n - 2)
现在的青蛙可以跳上1到n的任意级,按照之前的解题思路,依然先来看F(n),对于一个n级台阶来说
青蛙第一次可以跳1级,则还剩n - 1级台阶,即F(n - 1)
青蛙第一次可以跳2级,则还剩n - 2级台阶,即F(n - 2)
…
青蛙第一次可以跳n - 1级,则还剩1级台阶,即F(1)
青蛙第一次可以跳n级,即1种跳法
则F(n) = F(n - 1) + F(n - 2) + F(n - 3) + F(n - 4) + … + F(1) + 1
很显然F(1)= 1,在已知F(1)的情况下,我们可以利用递归解这道题,代码如下
实现代码
public int jumpFloorII(int number)
{
int count = 1;
for (int i = 1; i < number; i++)
{
count = count + jumpFloorII(number - i);
}
return count;
}
解法2
本题的递归算法由于编译器的低效实现不可避免的会存在大量的重复运算,我们可以在递归的基础上做一些优化,详细说明可以查看【剑指Offer】斐波那契数列。或者换一种思路,我们也可以不使用递归。有时候列出结果的前几项,找找规律,可能会有意想不到的收获
对于1级台阶,青蛙只有1 = 20种跳法
对于2级台阶,青蛙有2 = 21种跳法(分别是{1,1}, {2})
对于3级台阶,青蛙有4 = 22种跳法(分别是{1,1,1}, {1,2}, {2,1}, {3})
对于4级台阶,青蛙有8 = 23种跳法(分别是{1,1,1,1}, {1,1,2}, {1,2,1}, {2,1,1}, {2,2}, {1,3}, {3,1}, {4})
…
不难发现,对于n级台阶,总跳法数是2n-1
当然我们也可以通过公式推导出这个结果
由解法1可知
F(n) = F(n - 1) + F(n - 2) + F(n - 3) + F(n - 4) + … + F(1) + 1,则
F(n - 1) = F(n - 2) + F(n - 3) + F(n - 4) + … + F(1) + 1
两个式子合并可得F(n) = 2F(n - 1),则
F(n - 1) = 2F(n - 2)
F(n - 2) = 2F(n - 3)
即F(n) = 22F(n - 2),F(n) = 23F(n - 3)
以此类推,F(n)= 2n-1F(n - (n - 1)) = 2n-1F(1) = 2n-1
最终这道题被转换成如何求解2n-1,简单的方法是对2连乘n-1次,继续优化的话,可以使用整数的快速幂,【剑指Offer】斐波那契数列也已经有了详细的详解。下面仅放上本题的整数快速幂解法
实现代码
public int jumpFloorII(int number)
{
number = number - 1;
int count = 1;
int m = 2;
while (number > 0)
{
if ((number & 1) > 0)
{
count *= m;
}
m = m * m;
number = number >> 1;
}
return count;
}
解法3
对于求解2n-1,可以继续优化,利用左移运算,只使用一行代码就可以得到2n-1
对于数字1,左移1位是10,即2 = 21
左移2位是100,即4 = 22
左移3位是1000,即8 = 23
以此类推,左移n位,就是2n
要求2n-1,只需要将数字1左移n-1位,对应的代码如下
实现代码
public int jumpFloorII(int number)
{
return 1 << (number - 1);
}