[开心IT面试题] 爬楼梯问题豪华版

题目:

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

 

举例:

当n = 2,k = 2时,有12种方案

方案1:走1,走1

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

方案3:走1,走1,退1,走1,退1,走1

方案4:走2

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

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

方案7:走1,退1,走1,走1

方案8:走1,退1,走1,走1,退1,走1

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

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

方案11:走1,退1,走1,退1,走1,走1

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

 

思路:

所有解决方案可分为以下几种情况
1、没有往下走过
2、已经往下走过1次

3、已经往下走过2次
…、……
k-1、已经往下走过(k-1)次

k、已经往下走过k次

用Solution[k+1][3]二维数组表示上面所有方案。
第一维表示该方案中已经往下走过多少次。

第二维表示该方案中最后一步是多少个台阶。

 

当每多一个台阶时,根据已经往下走过多少次分情况处理:假设已经往下走过m次
1)所有方案基础上,再爬1个台阶
2)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶。
3)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶。
4)
所有方案基础上,可循环操作“爬1个台阶,然后往下走1个台阶”,再爬1个台阶。(最少循环0次,最多循环(k-m)次)

5)最后一次是爬1个台阶的方案,变成最后一步爬2个台阶,可循环操作“往下走1个台阶,再爬1个台阶”(最少循环0次,最多循环(k-m)次)
6)最后一次是爬2个台阶的方案,变成最后一步爬3个台阶,可循环操作“往下走1个台阶,再爬1个台阶”(最少循环0次,最多循环(k-m)次)

 

代码:

#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为总台阶数,k为爬楼梯过程中可以往下走的次数
BIGINT ClimbStairs3(int nSteps, int k)
{
    BIGINT allSolution;
    memset(&allSolution, 0, sizeof(BIGINT));

    if(nSteps < 1)
    {
        allSolution.BigInt[0] = '0';
        return allSolution;
    }else if(nSteps == 1)
    {
        allSolution.BigInt[0] = char(k+'1');
        return allSolution;
    }else
    {
        //nStep[x][y]代表所有方案,
        //x表示该方案中已经往下走过x次
        //y表示该方案中最后一步是(y+1)个台阶
        //如nStep[4][1]表示该方案已经往下走过4次,最后一步是2个台阶
        BIGINT (*nStep)[3];
        BIGINT (*tempStep)[3];
        nStep = new BIGINT[k+1][3];
        tempStep = new BIGINT[k+1][3];
        memset(nStep, 0, 3*(k+1)*sizeof(BIGINT));
        memset(tempStep, 0, 3*(k+1)*sizeof(BIGINT));

        //只有一个台阶时的解决方案
        for(int i = 0; i <= k; i++)
        {
            nStep[i][0].BigInt[0] = '1';
        }

        //从最少有2个台阶开始计算
        for(int i = 2; i <= nSteps; i++)
        {
            for(int x = 0; x <= k; x++)
            {
                //在所有方案中最后一步是2个台阶的变成3个台阶
                memcpy(&tempStep[x][2], &nStep[x][1], sizeof(BIGINT));
                //在所有方案中最后一步是1个台阶的变成2个台阶
                memcpy(&tempStep[x][1], &nStep[x][0], sizeof(BIGINT));
                //在所有方案中,继续再走1个台阶
                memcpy(&tempStep[x][0], &Add(tempStep[x][0], nStep[x][0]), sizeof(BIGINT));
                memcpy(&tempStep[x][0], &Add(tempStep[x][0], nStep[x][1]), sizeof(BIGINT));
                memcpy(&tempStep[x][0], &Add(tempStep[x][0], nStep[x][2]), sizeof(BIGINT));
                for(int y = x+1; y <= k; y++)
                {
                    //在所有方案中,循环(走一步,退一步),再走一步
                    memcpy(&tempStep[y][0], &Add(tempStep[y][0], nStep[x][0]), sizeof(BIGINT));
                    memcpy(&tempStep[y][0], &Add(tempStep[y][0], nStep[x][1]), sizeof(BIGINT));
                    memcpy(&tempStep[y][0], &Add(tempStep[y][0], nStep[x][2]), sizeof(BIGINT));
                    //在所有方案中最后一步是1个台阶的变成2个台阶,循环(退一步,再走一步)
                    memcpy(&tempStep[y][0], &Add(tempStep[y][0], nStep[x][0]), sizeof(BIGINT));
                    //在所有方案中最后一步是2个台阶的变成3个台阶,循环(退一步,再走一步)
                    memcpy(&tempStep[y][0], &Add(tempStep[y][0], nStep[x][1]), sizeof(BIGINT));
                }
            }
            memcpy(nStep, tempStep, 3*(k+1)*sizeof(BIGINT));
            memset(tempStep, 0, 3*(k+1)*sizeof(BIGINT));
        }
        for(int i = 0; i <= k; i++)
        {
            memcpy(&allSolution, &Add(allSolution, nStep[i][0]), sizeof(BIGINT));
            memcpy(&allSolution, &Add(allSolution, nStep[i][1]), sizeof(BIGINT));
            memcpy(&allSolution, &Add(allSolution, nStep[i][2]), sizeof(BIGINT));
        }
        delete[] tempStep;
        delete[] nStep;
        return allSolution;
    }
}

 

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

答案:爬楼梯问题

 

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

答案:爬楼梯问题升级版



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值