首页 > 代码库 > 跳台阶问题分析

跳台阶问题分析

问题描述:

         一个台阶,一次可以跳3级或者5级,跳到第n级有多少种跳法。

问题分析:

         刚开始的思路是,每次跳3级或者5级,不一定能跳到第n级,要求n是3的倍数,或者是5的倍数,或者是3i和5j的和(i>=0,j>=0)。所以考虑三种情况:

1、  n是3的倍数;

2、  n是5的倍数;

3、  3i+5j=n(i>=0且j>=0)。其他情况则是不可到达第n级。

情况1和情况2很容易,直接求倍数就可以。情况3考虑的是两层for循环,使用蛮力法找到满足条件的i和j的值。后来发现,情况1和情况2不需要在算法中写具体实现,不满足情况1和情况2,不可到达第n级,则跳法为0。

  另一种是递归。递归要满足两个条件:1、存在相同的情景,可以重复调用;2、存在最终的结束条件。

  最终的结束条件很容易想到,那就是最后只剩下3级台阶或者5级台阶的情况,一次可以跳完,只有一种跳法。相同的情景可以这么考虑,开始跳之前,还剩下n级台阶没有跳过,跳过一次后,比如跳3级或者5级,则剩下n-3或者n-5,再开始第二次跳,发现第二次跳和第一次跳面临的选择是相同的,也是跳3级或者5级,只是要跳的台阶数减少了3级或者5级。那么每次的跳是相同的情景,可以重复调用。如果用函数jumpCount(n)计算跳法的话,n级台阶的跳法即是jumpCount(n),按照递归的思路,如果第一次跳3级的话,则剩下n-3,再跳这n-3级台阶,这n-3级台阶的跳法是jumpCount(n-3)。同理,如果第一次跳5级的话,则剩下n-5级的跳法是jumpCount(n-5);以此递推,每次都是在剩下的台阶数中跳3级或者5级,剩下n-3或者n-5,再重复跳,一直到最后只剩下3级或者5级。那么n级台阶的跳法是jumpCount(n)= jumpCount(n-3)+ jumpCount(n-5)。其实这里发现和第一种思路的第3中情况是类似的。

         这里当时有个思想误区,首先确实是考虑到了将剩下的台阶数作为下次跳跃的总数,每次跳跃进行递归的调用。但是受第一种思路的影响,每次都在考虑n-3i或者n-5j的情况,没有想到递归的核心思想是整体与局部的思想,问题分大的模块来看待,每个小模块再一步一步细分。每个大模块和小模块是相似的关系。每个小模块只需要考虑一步,不需要考虑整体情况,所以不需要考虑i和j了。

问题验证:

蛮力法代码:

 1     /** 2      * 思路一:非递归,蛮力法找到满足条件的值 3      * @param n 待跳的台阶数 4      * @return 跳法 5      */ 6     public static int jumpCount1(int n) { 7         int count = 0;//跳法 8         //i最大不能超过n的约数,同理j 9         for (int i = 0; i <= n / 3; i++) {10             for (int j = 0; j <= n / 5; j++) {11                 if (3 * i + 5 * j == n) {12                     count++;//满足条件,则找到了一种跳法13                 }14             }15         }16 17         return count;18     }

递归代码:

 1     /** 2      * 思路二:递归 3      * @param n 待跳的台阶数。每次跳3级或者5级 4      * @return 跳法 5      */ 6     public static int jumpCount(int n) { 7         if (n < 3) { 8             return 0;//如果小于3,则跳不了 9         }10 11         if (n == 3 || n == 5) {12             return 1;//只剩下3级或者5级,则只有一种跳法,跳3级或者5级,一次跳完13         }14 15         return jumpCount(n - 3) + jumpCount(n - 5);//每次跳跃,剩下为n-3或者n-5,作为下次待跳跃的台阶数16     }

蛮力法时间复杂度为O(n^2),递归为O(n),递归时间复杂度优于蛮力法。递归算法明显优于蛮力法,简介清晰,但是数据量大的情况下运行效率较低,内存开销大。

总结:

1、  蛮力法很容易想到,思想误区是要跳出判断是否能跳到第n级台阶的情况,这种情况跳法就是0,不需要代码中判断。

2、  递归法要牢牢抓住递归的思想,考虑整体就不要管部分,考虑部分就不要管整体。

跳台阶问题分析