算法-有n步台阶,一次只能上1步或2步,共有多少种走法

本文详细解析了斐波那契数列的三种算法实现:递归、迭代及动态规划,对比了它们各自的优缺点,并通过实例验证了算法的有效性。

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

前言:
其实这个题目挺简单的,可以分分钟看懂,但是分析过程非常经典,故记录下来以后复习。

分析

1、n=0 和 n=1 的时候 并没有其他可选择的,所以可以得出f(0)=0;f(1)=1;
2、n>=2时情况就变复杂起来,但是这个时候可以操作的步骤也就2种
也就是走1步(n-1)与走2步(n-2)。所以可以得到f(n)=f(n-1)+f(n-2);
从当前状态转为下一状态的通用算法既可。
3、 验证,使用2以上的数字验证几次。

实现

实现算法往往是简单的,及时是复杂算法也花费不了太多精力,所以将问题转换为数学问题是一种很好的选择。当前这种简单算法实现方式更为简单,而且往往不止一种方式。

递归

public static int f(int n){
    if(n<=2) return n;
    int x = f(n-1)+f(n-2);
    return x;
}

优点:可能是最好理解的算法了把。代码简单,好理解。
缺点:计算次数颇多,有很多冗余计算。

迭代

public static int f(int n){
    if(n<=2) return n;
    if first=1,second=2;
    int third=0;
    for(int i=3;i<=n;i++){
        third = first+second;
        first = second;
        second = third;
    }
    return third;
}

优点: 基本没有冗余计算,效率高
缺点: 谁能一次读完就理解的?

动态规划

原文:动态规划是解决下面这些性质类问题的技术:
1. 一个问题可以通过更小子问题的解决方法来解决(译者注:即问题的最优解 包含了其子问题的最优解,也就是最优子结构性质)。
2. 有些子问题的解可能需要计算多次(译者注:也就是子问题重叠性质)。
3. 子问题的解存储在一张表格里,这样每个子问题只用计算一次。
4. 需要额外的空间以节省时间。

public static int[] A = new int[100];
public static int f(int n){
    if(n<=2){
        A[n] = n;
    }
    if(A[n]>0){
        return A[n];
    } else {
        A[n] = f(n-1)+f(n-2);
        return A[n];
    }
}

虽然没弄懂为啥叫动态规划,但是代码还是很清晰的。
优点:已经计算过的结果就不需要再次计算了。空间换时间
缺点:需要额外的开销。

<think>好的,我现在要解决这个问题:有n个台阶每次可以走1步或2,用递归的方法求有多少走法,并且用C语言实现。让我仔细想想该怎么处理。 首先,我得理解问题。题目是说,当有n级台阶时,每次可以跨1步或2,问总共有多少种不同的走法。需要用递归的方法来解决,并用C语言写出来。那递归的话,应该怎么分解这个问题呢? 可能的话,我需要找到一个递推关系。假设n=1的时候,只有一种走法,就是一走完。n=2的时候,有两种走法:两次一一次。那对于更大的n,比如n=3的情况,可以怎么考虑呢?比如第一1,剩下的就是2的问题,者第一2,剩下的就是1的问题。所以总共有f(3) = f(2)+f(1) =2+1=3种。这似乎符合斐波那契数列的规律? 那这样的话,递归的公式应该是f(n) = f(n-1) + f(n-2),当n>2的时候。而基例是f(1)=1,f(2)=2者有没有可能基例的处理需要调整?比如当n=0的时候,可能有1种方式(不走)?比如,当n=0,可能返回1?这时候,如果n=3的话,计算会是f(3)=f(2)+f(1)= (f(1)+f(0)) + f(0)+f(-1)? 这可能有问题。所以可能原来的思路是正确的,即基例是n=1和n=2的时候。 不过,在常见的跳台阶问题中,通常假设n=0的时候有一种走法,这样递归式就可以统一为f(n) = f(n-1)+f(n-2),其中f(0)=1,f(1)=1。这时候对于n=2,结果就是1+1=2,n=3的话是2+1=3,依此类推。这种情况下,递归的基例是n==0返回1,n<0返回0?者可能不同的定义方式。 但这里题目中的n应该是一个正整数,所以可能用户的问题中的n是从1开始的。那原来的基例可能设定为n=1返回1,n=2返回2。这个时候递归式是当n>2时,返回f(n-1)+f(n-2)。这样的话,当n=3时,是2+1=3,符合预期。那这样的递归式应该可以解决问题。 那接下来需要把这个思路写成C语言的递归函数。函数可能像这样: int countSteps(int n) { if (n == 1) return 1; if (n == 2) return 2; return countSteps(n-1) + countSteps(n-2); } 但是,这样递归的效率可能非常低,因为会重复计算很多次。例如计算f(5)会计算f(4)+f(3),而f(4)又会计算f(3)+f(2),这样f(3)会被多次计算。但题目要求的是用递归方法,所以可能不管效率的问题,只是要正确性。 不过这里需要注意基例是否正确。比如当n=0的时候,是否应该返回1?比如,如果用户输入的n是0,是否应该处理?但题目中的n应该是指至少有一个台阶的情况,所以可能假设n>=1。所以在代码中是否需要处理n<=0的情况呢?比如返回0者报错? 例如,如果用户传入n=0,当前的函数会进入n==1的判断,不满足,然后n==2的判断也不满足,然后返回countSteps(-1)+countSteps(-2),这显然会导致无限递归,直到堆栈溢出。所以可能需要在函数开始处处理n<=0的情况,返回0者错误提示。者,题目假设输入的n是正整数,不需要处理。但为了代码的健壮性,可能需要加上判断。 但根据题目要求,用户可能希望处理的是n>=1的情况。所以在代码中应该处理这些情况。例如: int countSteps(int n) { if (n < 1) return 0; // 处理无效输入 if (n == 1) return 1; if (n == 2) return 2; return countSteps(n-1) + countSteps(n-2); } 这样,当n=0者负数时返回0,其他情况正确计算。这是否符合题目的要求呢?题目可能需要的是当n是正整数时的解法,所以这样处理比较合理。 然后,用户可能需要一个完整的例子。例如,主函数中调用这个函数: #include <stdio.h> int countSteps(int n) { if (n < 1) return 0; if (n == 1) return 1; if (n == 2) return 2; return countSteps(n-1) + countSteps(n-2); } int main() { int n = 5; printf("当有%d个台阶时,共有%d种走法\n", n, countSteps(n)); return 0; } 当n=5时,计算过程是: f(5)=f(4)+f(3) f(4)=f(3)+f(2) f(3)=f(2)+f(1)=2+1=3 所以f(4)=3+2=5;f(5)=5+3=8。所以当n=5时,结果是8种。 那这样是否正确?根据斐波那契数列的规律,是的。例如,斐波那契数列定义为F(1)=1, F(2)=1, F(3)=2,但是这里的跳台阶问题结果对应的是斐波那契数列的F(n+1)。者要看具体定义。 例如,斐波那契数列通常定义为F(0)=0,F(1)=1,F(2)=1,F(3)=2,F(4)=3,F(5)=5。但这里的跳台阶问题,当n=1时有1种,n=22种,n=3有3种,n=4有5种,n=5有8种。对应的斐波那契数列的第n+1项。例如,斐波那契数列的F(5)是5,而这里的n=5时结果是8,即F(6)=8。这说明这里的递归式实际上是斐波那契数列的移位版本。不过这对解题来说并不影响,只需要按照正确的递推关系处理即可。 现在,总结一下骤: 1. 递归函数countSteps处理n级台阶的情况。 2. 基例:当n=1时返回1,n=2时返回2。 3. 递推式:返回countSteps(n-1) + countSteps(n-2)。 4. 处理无效输入,如n<=0时返回0。 这样就能得到正确的结果。当然,递归的效率问题存在,但对于教学理解递归思想来说,这样的实现是合适的。 可能的疑问是,当n=0时,是否应该返回1?比如,如果用户认为没有台阶的时候有一种走法(不跨),则基例可能需要调整。例如,如果函数允许n=0的话,那基例应为: if (n == 0) return 1; if (n == 1) return 1; 然后递归式是f(n) = f(n-1) + f(n-2)。这样,当n=2时,f(2)=f(1)+f(0)=1+1=2,这与之前的结果一致。但此时函数的参数n可以是非负整数。这种情况下,函数可能需要调整: int countSteps(int n) { if (n < 0) return 0; if (n == 0 || n == 1) return 1; return countSteps(n-1) + countSteps(n-2); } 这样,当n=0返回1,n=1返回1,n=2返回2,以此类推。这时候,对于n=5,返回的是8。所以两种不同的基例处理方式得到的结果是一样的,但处理n的范围不同。此时,原题中的n是否包含0的情况? 根据常规的跳台阶问题,通常可能认为n=0时有1种方法,但题目中的描述是“有n个台阶”,所以n应该是正整数。因此,原题可能更倾向于第一个版本的函数,即处理n>=1的情况,而当n=1返回1,n=2返回2者,可能需要根据具体情况调整。 例如,如果用户输入n=0,可能应该返回0,因为实际中没有台阶的话,无法走。者可能认为没有动作也是一种走法?这可能需要题目具体说明。但题目中的例子可能不需要处理这个情况,所以函数可以假设n>=1。 综上,正确的递归函数应该基于n的合法输入(n>=1),并正确处理基例。因此,给出的代码示例是合理的。 现在,检查一下是否有可能的错误。例如,当n=3时,函数返回3是否正确? 是的,因为走法有:1+1+1, 1+2, 2+1,三种情况,所以正确。当n=4时,得到5种,是否正确?是的,走法共有5种。所以递归函数是正确的。 所以最终的代码应该是正确的,符合题目的要求。</think>以下是使用递归方法求解n个台阶走法问题的C语言实现: ```c #include <stdio.h> int countSteps(int n) { // 处理无效输入 if (n < 1) return 0; // 基例条件 if (n == 1) return 1; // 1种方式:1 if (n == 2) return 2; // 2种方式:1+12 // 递归关系:f(n) = f(n-1) + f(n-2) return countSteps(n-1) + countSteps(n-2); } int main() { int n; printf("请输入台阶数:"); scanf("%d", &n); printf("共有%d种走法\n", countSteps(n)); return 0; } ``` ### 算法原理 1. **问题分析** 当走到第n个台阶时,最后一可能从第n-1阶跨1者从第n-2阶跨2。因此总走法数为这两种情况的走法数之和。 2. **递推关系** $$ f(n) = f(n-1) + f(n-2) $$ 3. **边界条件** - 当n=1时:只有1走法(直接走1- 当n=2时:有2走法(连续走21直接走2) ### 示例说明 例如当n=5时: $$ \begin{align*} f(5) &= f(4) + f(3) \\ &= (f(3)+f(2)) + (f(2)+f(1)) \\ &= ((f(2)+f(1))+2) + (2+1) \\ &= ((2+1)+2) + 3 \\ &= 8 \end{align*} $$ ### 复杂度分析 - **时间复杂度**:$O(2^n)$(存在大量重复计算) - **空间复杂度**:$O(n)$(递归调用栈深度) > 📢 提示:此递归解法效率较低,实际应用中建议使用动态规划优化(时间复杂度可降至$O(n)$)。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值