[开心IT面试题] 爬楼梯问题升级版

本文详细阐述了爬楼梯问题的解决思路与代码实现,包括基本问题、递归解法、迭代解法及优化策略,旨在提供一种高效计算从第0个台阶到达第n个台阶的不同路径数的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

如果每次可以往上爬1个或2个或3个台阶,爬楼梯过程中允许最多往下走一次,每次走1个台阶,从第0个台阶开始,爬到第n个台阶有多少种方案

 

举例:

当n = 1时,有2种方案。

方案一:走1个台阶

方案二:走1个台阶,退1个台阶,再走1个台阶

当n = 2时,有6种方案

方案一:走1,走1

方案二:走1,走1,退1,走1

方案三:走2

方案四:走2,退1,走1

方案五:走1,退1,走1,走1

方案六:走1,退1,走2

 

思路:

爬到第n-1个台阶时总方案f(n-1)中分为已经往下走过一次没有往下走过两种:

已经往下走过一次的所有方案中最后一步是1个台阶为AA(n-1),2个台阶为BB(n-1),3个台阶为CC(n-1)。
没有往下走过的所有方案中最后一步是1个台阶为A(n-1),2个台阶为B(n-1),3个台阶为C(n-1)。

即f(n-1)=AA(n-1)+BB(n-1)+CC(n-1)+A(n-1)+B(n-1)+C(n-1).

设爬到第n个台阶总方案数为f(n)(n > 3).

 

当每多一个台阶,分两部分处理:

在之前所有没有往下走过的方案中:
1)
所有方案基础上,再爬1个台阶,即A(n-1)+B(n-1)+C(n-1)种方案.
2)所有方案基础上,再爬1个台阶,然后往下走1个台阶,再爬1个台阶。即A(n-1)+B(n-1)+C(n-1)种方案.

3)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶。即A(n-1)种方案.
4)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶,然后往下走1个台阶,再爬1个台阶。即A(n-1)种方案.
5)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶。即B(n-1)种方案.

6)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶,然后往下走1个台阶,再爬1个台阶。即B(n-1)种方案.

在之前所有已经往下走过一次的方案中:
1)所有方案基础上,再爬1个台阶,即AA(n-1)+BB(n-1)+CC(n-1)种方案.
2)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶。即A(n-1)种方案.
3)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶。即B(n-1)种方案.

由两部分所有处理步骤可知,

f(n) = 4A(n-1)+4B(n-1)+2C(n-1)+2AA(n-1)+2BB(n-1)+CC(n-1)

 

代码:

#define BIT_TOTAL   500
typedef struct{
    char BigInt[BIT_TOTAL]; //BigInt[0]表示最高位
}BIGINT;

//将字符串反转
void Reverse(char nData[])
{
    char temp;
    for (int i = 0, j = strlen(nData)-1; (i != j) && (i - j != 1); i++, j--)
    {
        temp = nData[i];
        nData[i] = nData[j];
        nData[j] = temp;
    }
}

//大整数加法
BIGINT Add(BIGINT first, BIGINT second)
{
    BIGINT result;
    memset(&result, 0, sizeof(BIGINT));

    Reverse(first.BigInt);
    Reverse(second.BigInt);

    int temp = 0;
    int bit = 0;
    int length = strlen(first.BigInt) > strlen(second.BigInt) ? strlen(first.BigInt):strlen(second.BigInt);
    for (int i = 0; i < length; i++)
    {
        if(first.BigInt[i] == '\0')
        {
            first.BigInt[i] = '0';
        }
        if(second.BigInt[i] == '\0')
        {
            second.BigInt[i] = '0';
        }
        temp = (first.BigInt[i]-'0') + (second.BigInt[i]-'0') + bit;
        if (temp >= 10)
        {//有进位
            temp = temp % 10;
            bit = 1;
        }else
        {//无进位
            bit = 0;
        }
        result.BigInt[strlen(result.BigInt)] = char(temp + '0');
    }
    //判断是否要在最高位加一位数
    if (bit == 1)
    {
        result.BigInt[strlen(result.BigInt)] = char(bit + '0');
    }
    Reverse(result.BigInt);
    return result;
}

//nSteps为总台阶数
BIGINT ClimbStairs2(int nSteps)
{
    BIGINT noStep_1;        //noStep_1代表所有没有往下走过的方案中最后一步是1个台阶的方案
    BIGINT noStep_2;        //noStep_2代表所有没有往下走过的方案中最后一步是2个台阶的方案
    BIGINT noStep_3;        //noStep_3代表所有没有往下走过的方案中最后一步是3个台阶的方案
    BIGINT yesStep_1;       //yesStep_1代表所有已经往下走过一次的方案中最后一步是1个台阶的方案
    BIGINT yesStep_2;       //yesStep_2代表所有已经往下走过一次的方案中最后一步是2个台阶的方案
    BIGINT yesStep_3;       //yesStep_3代表所有已经往下走过一次的方案中最后一步是3个台阶的方案
    BIGINT allSolution;
    BIGINT tempCount;
    memset(&noStep_1, 0, sizeof(BIGINT));
    memset(&noStep_2, 0, sizeof(BIGINT));
    memset(&noStep_3, 0, sizeof(BIGINT));
    memset(&yesStep_1, 0, sizeof(BIGINT));
    memset(&yesStep_2, 0, sizeof(BIGINT));
    memset(&yesStep_3, 0, sizeof(BIGINT));
    memset(&allSolution, 0, sizeof(BIGINT));
    memset(&tempCount, 0, sizeof(BIGINT));

    //只有一个台阶时的解决方案
    noStep_1.BigInt[0] = '1';
    yesStep_1.BigInt[0] = '1';

    if(nSteps < 1)
    {
        allSolution.BigInt[0] = '0';
        return allSolution;
    }else if(nSteps == 1)
    {
        allSolution.BigInt[0] = '2';
        return allSolution;
    }else
    {
        allSolution.BigInt[0] = '2';
        //从最少有2个台阶开始计算
        for(int i = 2; i <= nSteps; i++)
        {
            //在已经往下走过一次的方案中最后一步是2个台阶的变成3个台阶
            memcpy(&yesStep_3, &yesStep_2, sizeof(BIGINT));
            //在已经往下走过一次的方案中最后一步是1个台阶的变成2个台阶
            memcpy(&yesStep_2, &yesStep_1, sizeof(BIGINT));
            //在所有已经往下走过一次的方案中,继续再走一步
            //在所有没有往下走过的方案中,再走一步,然后退一步,再走一步
            //在所有没有往下走过的方案中最后一步是1个台阶的变成2个台阶,然后退一步,再走一步
            //在所有没有往下走过的方案中最后一步是2个台阶的变成3个台阶,然后退一步,再走一步
            memcpy(&yesStep_1, &allSolution, sizeof(BIGINT));
            memcpy(&yesStep_1, &Add(yesStep_1, noStep_1), sizeof(BIGINT));
            memcpy(&yesStep_1, &Add(yesStep_1, noStep_2), sizeof(BIGINT));
            //在所有没有往下走过的方案中,继续再走一步
            memcpy(&tempCount, &Add(noStep_1, noStep_2), sizeof(BIGINT));
            memcpy(&tempCount, &Add(tempCount, noStep_3), sizeof(BIGINT));
            //在所有没有往下走过的方案中最后一步是2个台阶的变成3个台阶
            memcpy(&noStep_3, &noStep_2, sizeof(BIGINT));
            //在所有没有往下走过的方案中最后一步是1个台阶的变成2个台阶
            memcpy(&noStep_2, &noStep_1, sizeof(BIGINT));
            memcpy(&noStep_1, &tempCount, sizeof(BIGINT));

            memcpy(&allSolution, &Add(noStep_1, noStep_2), sizeof(BIGINT));
            memcpy(&allSolution, &Add(allSolution, noStep_3), sizeof(BIGINT));
            memcpy(&allSolution, &Add(allSolution, yesStep_1), sizeof(BIGINT));
            memcpy(&allSolution, &Add(allSolution, yesStep_2), sizeof(BIGINT));
            memcpy(&allSolution, &Add(allSolution, yesStep_3), sizeof(BIGINT));
        }
        return allSolution;
    }
}

原始题目:如果每次可以往上爬1个或2个或3个台阶,不能往下走,从第0个台阶开始,爬到第n个台阶有多少种方案?

答案:爬楼梯问题

 

扩展题目:如果每次可以往上爬1个或2个或3个台阶,爬楼梯过程中允许最多往下走k次,每次走1个台阶,从第0个台阶开始,爬到第n个台阶有多少种方案?

答案:爬楼梯问题豪华版



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值