《剑指Offer》读书笔记09:变态青蛙跳


题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
求该青蛙跳上一个n级的台阶总共有多少种跳法。


解题思路

变态青蛙跳

因为青蛙一次可以跳1,2,3…n级台阶。
1. 求F(1),
青蛙跳一次1级台阶,
F(1) = 1 = 2 11 };
2. 求F(2),
青蛙在1级台阶{即F(1)},从1级台阶直接跳到2级台阶,跳法种类F(1)
青蛙直接从最下面跳到2级台阶,跳法种类1
F(2)=F(1)+1 = 2 = 2 21 ;
3. 求F(3),
青蛙在1级台阶{即F(1)},从1级台阶直接跳到3级台阶,跳法种类F(1)
青蛙在2级台阶{即F(2)},从2级台阶直接跳到3级台阶,跳法种类F(2)
青蛙直接从最下面跳到3级台阶,跳法种类1
F(3)=F(2)+F(1)+1 = 4 = 2 31 ;
4. 求F(4),
青蛙在1级台阶{即F(1)},从1级台阶直接跳到4级台阶,跳法种类F(1)
青蛙在2级台阶{即F(2)},从2级台阶直接跳到4级台阶,跳法种类F(2)
青蛙在3级台阶{即F(3)},从3级台阶直接跳到4级台阶,跳法种类F(3)
青蛙直接从最下面跳到4级台阶,跳法种类1
F(4)=F(3)+F(2)+F(1)+1 = 8 = 2 41 ;
5. 求F(5), 如上图
青蛙在1级台阶{即F(1)},从1级台阶直接跳到5级台阶,跳法种类F(1)
青蛙在2级台阶{即F(2)},从2级台阶直接跳到5级台阶,跳法种类F(2)
青蛙在3级台阶{即F(3)},从3级台阶直接跳到5级台阶,跳法种类F(3)
青蛙在4级台阶{即F(4)},从4级台阶直接跳到5级台阶,跳法种类F(4)
青蛙直接从最下面跳到5级台阶(虚线处),跳法种类1
F(5)=F(4)+F(3)+F(2)+F(1)+1 = 16 = 2 51 ;

求F(n),
青蛙先跳到1级台阶{即F(1)},从1级台阶直接跳到n级台阶,跳法种类F(1)
青蛙先跳到2级台阶{即F(1)},从2级台阶直接跳到n级台阶,跳法种类F(2)
青蛙先跳到3级台阶{即F(1)},从3级台阶直接跳到n级台阶,跳法种类F(3)

青蛙先跳到n-1级台阶{即F(n-1)},从n-1级台阶直接跳到n级台阶,跳法种类F(n-1)
青蛙直接从最下面跳到n级台阶,跳法种类1
F(n)=F(n-1)+…+F(3)+F(2)+F(1)+1 = 2 n1 ;


参考代码

/*
计算F(n)= 2^(n-1)
在牛客网编译通过,有改动(类型int改为long double,用来测试这些算法能测试的极限)
思路:
1. 先求出2^n,再除以2.
2. 求2^n,相当于n个2相乘。
3. 举例说明,比如求2^99,即99个2相乘,即f(99)。
4. f(1)*f(1)=f(2); f(2)*f(2)=f(4); f(4)*f(4)=f(8); f(8)*f(8)=f(16);
   f(16)*f(16)=f(32); f(32)*f(32)=f(64);
5. 步骤4中f(64)再平方一次,就能求出f(128),已经超过f(99),不能求出我们需要的值。
6. 步骤4后,只需要再求出f(99-64)=f(35),与f(64)相乘即可。
7. 同样的方法求f(35)。
优点:
循环,不耗费额外空间
缺点:
不如递归容易理解
代码不如递归清晰简洁
*/
long double jumpFloorII(int number) {
    clock_t clockStart = clock();
    cout << "clockStart1= " << clockStart << endl;
    if ( number <= 0 ) {
        return 0;
    } 

    long double sum = 1.0;
    long double tmpSum = 2.0;
    int count = 1;
    while ( count <= number ) {
        count *= 2;
        if ( count < number ) {
            tmpSum *= tmpSum;
        } else if ( count == number ) {
            tmpSum *= tmpSum;//平方
            sum *= tmpSum;
            break;
        } else {
            count /= 2;
            number -= count;
            sum *= tmpSum;
            if ( number == 1 ) {
                sum *= 2;
                break;
            } else {
                tmpSum = 2;
                count = 1;
            }
        }
    }
    clock_t clockEnd = clock();
    cout << "clockEnd1= "<< clockEnd <<endl;
    cout << "clockTime1= "<< clockEnd-clockStart <<endl;
    return sum/2.0;
}

an={a(n1)/2a(n1)/2a,an/2an/2,nn

/*
思路如上
*/
long double jumpFloorIII(int number) {
    if ( number <= 0 ) {
        return 0.0;
    }
    if ( number == 1 ) {
        return 2.0;//递归出口
    }
    long double result = jumpFloorIII(number>>1);
    result *= result;
    if ( number & 1 ) {//奇数
        result *= 2;
    }
    return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
    //-----------变态青蛙跳--------------------------
    cout << jumpFloorII(1023) <<endl;

    clock_t clockStart = clock();
    cout << endl << endl;
    cout << "clockStart2= " << clockStart << endl;
    cout << jumpFloorIII(1022) <<endl;
    clock_t clockEnd = clock();
    cout << "clockEnd2= "<< clockEnd <<endl;
    cout << "clockTime2= "<< clockEnd-clockStart <<endl;

    int k = 0;
    return 0;
}

打印结果

变态青蛙跳打印结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值