青蛙跳台阶问题的三种解法

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

这道题还被ITEye放在了博文视点杯有奖答题活动里面。

 

我提供三种解法。

 

1、递归求解:

青蛙每跳一次前,有这样三种情况:

(1)只剩1级或0级台阶了,只能跳一步或者无法再跳了,那么这条路也走到了终点,走法的种类数可以加1;

(2)可以走2级台阶;

(3)可以走1级台阶。

于是递归方法求解:

	/**
	 * 递归方法
	 */
	public static int calc(int n) {
		return recursiveCalc(n, 0);
	}

	private static int recursiveCalc(int n, int total) {
		if (1 == n || 0 == n)
			return ++total;

		total = recursiveCalc(n - 1, total);
		return recursiveCalc(n - 2, total);
	}

 

 

2、概率论思路求解:

首先把问题抽象成简单的数学模型,设2步台阶跳了x次,1步台阶跳了y次,那么:

2x + y = n

于是,当 x = i ,可知 x >= 0 ,且 x < n/2 (向下取整),设某时刻的 x = i ,那么有 y = n - 2 * x ,于是,总共需要走 z = i + n - 2 * x 步。

这时,问题即转化为:

z步骤中,有x个两步,y个一步,相当于z个空当,由x、y去填充,那么不同填充方法的数目符合概率公式:

C(x,z) = z! / ((z-x)!x!)

即从排列z中取其中x个数的种类,x内部无序:

	/**
	 * 概率论
	 */
	public static int calc2(int n) {
		int total = 0;
		for (int i = 0; i <= n / 2; i++)
			total += factorial((i) + (n - 2 * i)) / factorial(i)
					/ factorial(n - 2 * i);
		return total;
	}

	private static int factorial(int n) {
		if (0 == n)
			return 1;

		int total = 1;
		for (int i = 1; i <= n; i++)
			total *= i;
		return total;
	}

 

 

3、数学归纳法求解:

如果n=1,总步数f(n)=1;如果n=2,总步数f(n)=2。

另一方面,当n>=3,当前还剩的步数f(n),如果接下去跳一步,那么还剩下的步数是f(n-1);如果接下去跳两步,那么还剩下的步数是f(n-2),故:f(n)=f(n-1)+f(n-2)

现设s3=f(n),s2=f(n-2),s1=f(n-1),从时间、空间复杂度来说,这也是最简单的一种方法:

	/**
	 * 数学归纳法
	 */
	public static int calc3(int n) {
		if (1 == n || 2 == n)
			return n;

		int s1 = 1, s2 = 2, s3 = 1;
		for (int i = 3; i <= n; i++) {
			s3 = s1 + s2;
			s1 = s2;
			s2 = s3;
		}
		return s3;
	}

 

 

聪明的你,还有什么办法?

欢迎和我讨论。 :)

 

文章系本人原创,转载请注明作者和出处

<think>好的,我现在要解决用户关于C语言实现青蛙台阶问题的代码示例请求。首先,我需要回忆这个问题的基本概念。青蛙台阶问题通常是一个递归或动态规划的经典例子,问题描述是:一只青蛙一次可以上1级或2级台阶,求上n级台阶有多少种不同的法。 用户明确提到需要C语言的代码示例,所以我需要确保提供的代码符合C语法。根据之前的引用,用户可能已经看过递归和动态规划的解决方案,但可能需要更详细的解释或不同的实现方式。 首先,我应该考虑递归方法。递归的基例是当n=1时只有一种方法,n=2时有两种方法。对于n>2的情况,法数目等于前两次法的总和,即f(n) = f(n-1) + f(n-2)。不过递归方法在n较大时会有重复计算的问题,效率低下。 接下来,动态规划方法可以优化这个问题。通过保存中间结果,避免重复计算。例如,使用一个数组来存储每个台阶数的法数,逐步计算到n。 另外,用户提供的引用[1]中的代码示例使用了位运算,当n阶时返回1 << (n-1),这似乎对应的是每次可以任意阶数的情况,即2^(n-1)种法。这可能是一个升级版的问题,允许青蛙1到n级台阶。需要明确用户的问题版本,但用户现在的问题可能还是传统的每次1或2级,所以需要确认。 不过用户当前的查询是传统的青蛙台阶问题,所以应该提供递归和动态规划的代码示例。同时,可能需要指出不同问题变体的区别,避免混淆。 现在,我需要检查引用中的代码是否正确。引用[1]中的jump函数返回1 << (n-1),即2的(n-1)次方,这适用于每次可以任意阶的情况,而传统的每次1或2级的情况应使用斐波那契数列的方式。因此,在回答中需要区分这两种情况,并明确说明用户的问题对应哪种情况。 用户可能混淆了这两种变体,所以需要明确提问,但根据用户的问题描述,他可能想要传统的解决方案。因此,我需要同时给出两种情况的解释和代码,或者确认用户的需求。 不过用户的问题直接提到“青蛙台阶问题”,通常默认是每次1或2级,所以应该以这种情况为主。但引用中的代码示例是另一种情况,因此需要指出两者的不同,并给出正确的代码。 接下来,我需要编写递归和动态规划的代码示例。例如: 递归版本: int jump(int n) { if (n <= 2) return n; return jump(n-1) + jump(n-2); } 动态规划版本: int jump(int n) { if (n <= 2) return n; int dp[n+1]; dp[1] = 1; dp[2] = 2; for (int i=3; i<=n; i++) dp[i] = dp[i-1] + dp[i-2]; return dp[n]; } 同时,可以优化动态规划的空间复杂度,只用两个变量保存前两个值: int jump(int n) { if (n <= 2) return n; int a = 1, b = 2, c; for (int i=3; i<=n; i++) { c = a + b; a = b; b = c; } return b; } 此外,需要解释这两种方法的时间复杂度和适用场景,递归在n大时效率低,动态规划更优。 可能还需要提到数学公式,比如斐波那契数列的通项公式,但实际编程中可能不常用。 最后,根据引用[2]中的内容,强调动态规划的优势,避免重复计算,适合大规模问题。同时,引用中的示例可能涉及升级版问题,即允许任意阶,这时法数是2^(n-1),如引用[1]的代码所示。因此,在回答中需要区分这两种情况,提供两种变体的代码,并解释它们的区别。 总结步骤: 1. 介绍青蛙台阶问题的两种变体:传统(每次1或2阶)和升级版(任意阶)。 2. 分别给出两种情况的C语言代码示例。 3. 解释递归和动态规划的实现及其优缺点。 4. 引用提供的资料中的代码,指出对应的变体。 5. 生成相关问题,帮助用户深入理解。</think>### C语言实现青蛙台阶算法 青蛙台阶问题有两种常见变体,需根据题目要求选择对应解法: --- #### **变体1:每次1或2级台阶(斐波那契数列问题)** **问题描述** 青蛙每次可以1级或2级台阶,求上$n$级台阶的总法数。 ##### 1. 递归实现(时间复杂度$O(2^n)$) ```c #include <stdio.h> int jump(int n) { if (n <= 2) return n; // 直接返回n(n=1时1种,n=2时2种) return jump(n - 1) + jump(n - 2); // 递推公式 } int main() { int num; printf("请输入台阶数: "); scanf("%d", &num); printf("总法数: %d\n", jump(num)); return 0; } ``` ##### 2. 动态规划实现(时间复杂度$O(n)$) ```c #include <stdio.h> int jump(int n) { if (n <= 2) return n; int a = 1, b = 2, c; for (int i = 3; i <= n; i++) { c = a + b; // 状态转移 a = b; b = c; } return b; } int main() { int num; printf("请输入台阶数: "); scanf("%d", &num); printf("总法数: %d\n", jump(num)); return 0; } ``` --- #### **变体2:每次可1~n级台阶(数学规律问题)** **问题描述** 青蛙每次可以1级、2级……直到$n$级台阶,求上$n$级台阶的总法数。 **公式推导** 总法数为$2^{n-1}$,可通过位运算高效计算[^1]。 ##### 代码实现(时间复杂度$O(1)$) ```c #include <stdio.h> int jump(int n) { return 1 << (n - 1); // 位运算计算2^(n-1) } int main() { int num; printf("请输入台阶数: "); scanf("%d", &num); printf("总法数: %d\n", jump(num)); return 0; } ``` --- ### 关键区别 | 特征 | 变体1(1或2级) | 变体2(1~n级) | |----------------|-------------------|-------------------| | 递推公式 | $f(n)=f(n-1)+f(n-2)$ | $f(n)=2^{n-1}$ | | 最优解法 | 动态规划 | 位运算 | | 时间复杂度 | $O(n)$ | $O(1)$ | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值