• 腾讯面试题:50个阶梯,你一次可以上一阶或两阶,走上去,共有多少种走法【原】


    有个同学去了腾讯,他说面试时有这么一道思维题:50个阶梯,你一次可以上一阶或两阶,走上去,共有多少种走法?

    我的思路: 

    我的思维比较直线简单:

    1,求出走上去可能有的方式,这里的方式是指:共走多少个1步,多少个2步。比如说,你走了2个1步,其余走2步,要走24个2步,用对象存起来就是:{one:2,two:24}

    2,每个方式的走法是可以通过排列组合公式算出来的。如下是排列组合公式:

         排列组合公式

     3,用到的公式是c(n,r)=n!/r!(n-r)!;这个比较好实现,无非就是阶乘除阶乘。

    代码如下:

            (function() {
                
    var waysArr = []; //上台阶方式的,每一种方式为一个对象字面量,如[{one:2,two:24},{one:4,two:23}]
                var counts = []; //存每种方式排列组合数
                //生成waysArr
                for (var i = 25; i >= 0; i--) {
                    
    var x = 50 - 2 * i;
                    waysArr.push({ one: x, two: i });
                }
                
    //阶乘
                function factorial(num) {
                    
    if (num <= 1) {
                        
    return 1;
                    }
                    
    else {
                        
    return num * arguments.callee(num - 1);
                    }
                }

                
    //每种方式的排列数
                //参数是走1步的次数,走2步的次数
                function thisWayTimes(one, two) {
                    
    //排列组合公式: n!/r!(n-r)!
                    //穷举--求得被除数
                    var ExhaustiveTimes = factorial(one + two);
                    
    //重复的次数---求得除数
                    var repeatedTimes = factorial(one) * factorial(two);
                    
    //算出次数---相除
                    var thisWayTime = ExhaustiveTimes / repeatedTimes;
                    
    //存进数组
                    counts.push(thisWayTime);
                }

                
    //计算每种方式的,除去全1全2,存入数组
                for (var j = 0, waysLen = waysArr.length; j < waysLen; j++) {
                    
    if (waysArr[j].one != 0 && waysArr[j].one != 50) {
                        thisWayTimes(waysArr[j].one, waysArr[j].two);
                    }
                }

                
    //求和函数
                function arrayNumSum(len) {
                    
    if (len <= 0) {
                        
    return 0;
                    } 
    else {
                        
    return counts[len] + arguments.callee(len - 1);
                    }
                }

                
    //求和,包括全1全2
                countsSum = arrayNumSum(counts.length - 1+ 2//计算出来共是20,365,010,749次
                alert(countsSum);
            })();

     后来正解出来,我的答案是不对,又不全错,因为排列组合公式做了除法运算,js算出来的结果不精确。

    (这就是没有找到真正数学规律的方案,费力不讨好)

     peter.liu的思路:

     以一个台阶为迈步的单位, 每次迈步都只有三种可能: 
    1.一次走完了一个台阶, 这种情况用 ‘O’表示.  (One的首字母)
    2.一次走两个台阶, 但是只走到前一半, 脚还在空中悬着, 没放下. 这种情况用’T1’表示. (Two的首字母)
    3.一次走两个台阶, 这次走的是后一半, 也就是脚从空中放下的过程. 这种情况用’T2’表示.
    假设这个人开始走
    1.走第一个台阶他有两个选择: ‘O’, 和 ‘T1’
    2.走第二个台阶他的选择取决于第一个台阶怎么走的:
       a.前一个台阶如果是’O’和’T2’, 这个台阶就有两个选择: ’O’和’T1’
       b.前一个台阶如果是’T1’, 那么这个台阶就只能是’T2’.  (悬着的脚总要放下来才行啊)
    3.走第三个台阶的方式, 取决于第二个台阶是怎么走的
    4.走第n个台阶的方式, 取决于第n-1个台阶只怎么走的.
    可以把他的每一步想象成一棵多叉树的节点, 下一步有多种走法, 那么节点就分叉. 这棵树一直到50层, 第50层有多少个叶节点, 就一共有多少种走法. 每一种走法, 都代表了从根节点到某一叶节点的那条路径.
    当然, 有一个问题, 最后一层的节点类型是不能为’T1’的, 否则悬着的脚就放不下来了.

    代码如下: 

    (function(){

    function steps(n){
        
    if (n === 1)
            
    return ['O''T1']; //第一步两种可能
        lastSteps = steps(n-1);
        
    var currentSteps = [];
        
    for(var i = 0; i< lastSteps.length; i++){
            
    var lastStep = lastSteps[i];
            
    if(lastStep === 'O' || lastStep === 'T2')
                currentSteps.push(
    'O''T1');
            
    else if(lastStep === 'T1')                                              
                currentSteps.push(
    'T2');        
        }
        
    return currentSteps;
    }

    var result = steps(20);
    result 
    = result.filter(function(item, index){return item !== 'T1'}); //最后一步不能是'T1', 过滤掉
    console.log(result.length);

    })();
    最终发现, 到30层的时候, 结果已经是100多万了, 并且以指数级增长. 运算第50层的时候会卡死, 因为可能性太多运算量太大了. 

    (这种思路很好,很巧妙,可惜就是运算量太大)

     费波拉希数列:

     peter的方法虽然不能求得50层的次数,但是可以求得前30多层。依次如下:

    一共1个台阶的话有1种走法.

    一共2个台阶的话有2种走法.

    一共3个台阶的话有3种走法.

    一共4个台阶的话有5种走法.

    一共5个台阶的话有8种走法.

    一共6个台阶的话有13种走法.

    一共7个台阶的话有21种走法.

    一共8个台阶的话有34种走法.

    一共9个台阶的话有55种走法.

    一共10个台阶的话有89种走法.

    一共11个台阶的话有144种走法.

    一共12个台阶的话有233种走法.

    一共13个台阶的话有377种走法.

    一共14个台阶的话有610种走法.

    一共15个台阶的话有987种走法.

    一共16个台阶的话有1597种走法.

    一共17个台阶的话有2584种走法.

    一共18个台阶的话有4181种走法.

    一共19个台阶的话有6765种走法.

    一共20个台阶的话有10946种走法.

    一共21个台阶的话有17711种走法.

    一共22个台阶的话有28657种走法.

    一共23个台阶的话有46368种走法.

    一共24个台阶的话有75025种走法.

    一共25个台阶的话有121393种走法.

    一共26个台阶的话有196418种走法.

    一共27个台阶的话有317811种走法.

    一共28个台阶的话有514229种走法.

    一共29个台阶的话有832040种走法.

    一共30个台阶的话有1346269种走法.

    一共31个台阶的话有2178309种走法.

    一共32个台阶的话有3524578种走法.

    一共33个台阶的话有5702887种走法.

    一共34个台阶的话有9227465种走法.

    一共35个台阶的话有14930352种走法.

    ......

    这不正是个费波拉希数列!!!!

     知道这个数学规律就好办了。代码如下:


            
    function fib(n) {
                
    return function(n, a, b) {
                    
    return n > 0 ? arguments.callee(n - 1, b, a + b) : a;
                } (n, 
    01);
            }
            fib(
    0); //0
            fib(1); //1
            fib(2); //1
            fib(3); //2
            fib(4); //3
            //......
            fib(50); //12586269025
            fib(51); //20365011074,这里是上到第50个阶梯

     我想大家会有很多其它解法,欢迎留言讨论。

     本文系原创,转载请声明出处(http://www.cnblogs.com/flowerszhong/

  • 相关阅读:
    SpatiePermissionPermissionServiceProvider' not found
    ThinkPad L14G 连接外接显示屏无响应问题解决
    HBase 初学习之数据模型
    python 实现 kakfa 的 生产消费模式 和 发布订阅模式
    数据结构中树的基本概念
    MySQL行级锁、表级锁、页级锁详细介绍
    设置div只显示2行
    linux 关闭防护墙,永久关闭
    yum install nginx 时报错:No package nginx available.
    win10 查询端口,杀掉端口进程
  • 原文地址:https://www.cnblogs.com/flowerszhong/p/2176374.html
Copyright © 2020-2023  润新知