算法练习

题目

  小鱼儿要上一个n阶的台梯,他每次可以上1阶或2阶,问他上n阶的共有多少种方法,比如n等于3,输出3 

分析

台阶数n取值种类方法数S
1(1)1
2(1,1),(2)2
3(1,1,1),(1,2),(2,1)3
4(1,1,1,1),(1,1,2),(1,2,1),(2,1,1),(2,2)5
5(1,1,1,1,1),(1,1,1,2),(1,1,2,1),(1,2,1,1),(1,2,2),(2,1,1,1),(2,1,2),(2,2,1)8
6(1,1,1,1,1,1),(1,1,1,1,2),(1,1,1,2,1),(1,1,2,1,1)(1,1,2,2),(1,2,1,1,1),(1,2,1,2),(1,2,2,1),
(2,1,1,1,1),(2,1,1,2),(2,1,2,1),(2,2,1,1),(2,2,2)
13
7(1,1,1,1,1,1,1),(1,1,1,1,1,2),(1,1,1,1,2,1),(1,1,1,2,1,1),(1,1,1,2,2),(1,1,2,1,1,1),(1,1,2,1,2),
(1,1,2,2,1),(1,2,1,1,1,1),(1,2,1,1,2),(1,2,1,2,1),
(1,2,2,1,1,),(1,2,2,2),(2,1,1,1,1,1),(2,1,1,1,2),(2,1,1,2,1),(2,1,2,1,1),(2,1,2,2),(2,2,1,1,1),(2,2,1,2),(2,2,2,1)
21
8(1,1,1,1,1,1,1,1),(1,1,1,1,1,1,2),(1,1,1,1,1,2,1),(1,1,1,1,2,1,1),(1,1,1,1,2,2),(1,1,1,2,1,1,1),(1,1,1,2,1,2),
(1,1,1,2,2,1),(1,1,2,1,1,1,1),(1,1,2,1,1,2),(1,1,2,1,2,1),(1,1,2,2,1,1),(1,1,2,2,2),(1,2,1,1,1,1,1),(1,2,1,1,1,2),
(1,2,1,1,2,1),(1,2,1,2,1,1),(1,2,1,2,2),(1,2,2,1,1,1),(1,2,2,1,2),(1,2,2,2,1),(2,1,1,1,1,1,1),(2,1,1,1,1,2),(2,1,1,1,2,1)
,(2,1,1,2,1,1),(2,1,1,2,2),(2,1,2,1,1,1),(2,1,2,1,2),(2,1,2,2,1)
,(2,2,1,1,1,1),(2,2,1,1,2),(2,2,1,2,1),(2,2,2,1,1),(2,2,2,2)
34
9.......55
 ....... 
n-2.......S(n-2)
n-1.......S(n-1)
n.......S(n-2)+S(n-1)

     由上表可以看出,对于给定一个台阶n,当台阶数目为n<3时,能上n阶台阶的方法为S = n,当台阶数n>=3时,能上台阶数S = S(n-1) + S(n-2).

解法1:递归算法

(1)当0 < n < 3,时 S(n) = n;

(2)当 n >= 3 时, S(n)  = S(n - 1) + S(n - 2); 然而当 n - 2 > 1 时, S(n - 1) = S( n - 2) + S( n  - 3)

(3)反复递归调用(1),(2)步骤组成的方法,直到最后传入的n值为<3时,即可求得结果(注:(1)为函数递归调用的出口)!

解法2: 采用保存先前计算的数据

将之前第一回计算的数据先保存到一个集合saveList中,下次需要时直接获取

比如计算f(5)=f(4)+f(3) ,f(3)=f(2)+f(1) ,f(4)=f(3)+f(2) ,f(3)=f(2)+f(1);

当计算f(5)时,采用从前往后方式进行计算,先计算f(1),f(2)将数据保存在saveList集合中,计算f(3)时

直接用计算saveList.get(0) + saveList.get(1)的值存入saveList中,此时saveList的大小为3,
同样计算f(4)时进行计算saveList.get(1) + saveList.get(2)的值存入saveList中,依次类推
最后返回saveList最后一个数据即可

相比与第一种方法,此处效率更高点


示例代码(仅供参考)

/**
 * 小鱼儿要上一个n阶的台梯,他每次可以上1阶或2阶,问他上n阶的共有多少种方法,比如n等于3,输出3
 * 
 * @author bianjie
 *
 */

public class Test1 {

	/**
	 * 统计方法1:采用递归算法
	 *    缺点:执行效率太低,存在重复计算问题,会出现栈溢出,
	 *    当输入的台阶步数step太大时,比如100,将会出现长时间等待计算问题
	 *    
	 *    栈溢出就是指你一个函数递归太多次导致的栈内存溢出,那么分析为什么会递归太多次,
	 *    比如算f(5)=f(4)+f(3)   f(3)=f(2)+f(1); f(4)=f(3)+f(2) f(3)=f(2)+f(1);
	 *    最后得出结果,这样算可以发现f(3)重复算了两次,如果给个更大的数就不用解释了,
	 *    这种写法时间复杂度是O(2的n次方),要解决的问题是重复计算
	 * @param step   台阶数
	 * @return 太阶数对应的可走的方法数
	 */
	public static int countMethod1(int step) {
		int total = 0;
		// 台阶步数小于3,递归函数的出口
		if (step < 3) {
			if (step == 1) {
				total = 1;
			} else if (step == 2) {
				total = 2;
			}
		} else {
			// 台阶数大于3,可走的方法数 S(n)= 比它小一个台阶的方法数S(n - 1)+比它小俩个台阶的方法数S(n - 2)
			total = countMethod1(step - 1) + countMethod1(step - 2);
		}
		return total;
	}

	
	
	
	//数据缓存
	public List<Integer> saveList = new ArrayList<Integer>();
	
	/**
	 *  统计方法1:采用保存先前计算的数据
	 *  		将之前第一回计算的数据先保存到saveList集合中,下次需要时直接获取
	 *  比如计算f(5)=f(4)+f(3) ,f(3)=f(2)+f(1) ,f(4)=f(3)+f(2) ,f(3)=f(2)+f(1);
	 *     当计算f(5)时,采用从前往后方式进行计算,先计算f(1),f(2)将数据保存在saveList集合中,计算f(3)时
	 *  直接用计算saveList.get(0) + saveList.get(1)的值存入saveList中,此时saveList的大小为3,
	 *  同样计算f(4)时进行计算saveList.get(1) + saveList.get(2)的值存入saveList中,依次类推
	 *  最后返回saveList最后一个数据即可
	 *   	相比与第一种方法,此处效率更高点
	 * @param size   台阶步数
	 * @return  最后可走的方法数
	 */
	public int countMethod2(int step) {
		saveList.add(1);
		saveList.add(2);
		if (step >= 3) {
			for (int startIndex = 1; startIndex < step; startIndex++) {
				int newData = saveList.get(startIndex) + saveList.get(startIndex - 1);
				saveList.add(newData);
			}
		}
		return saveList.get(step - 1);
	}

	public static void main(String[] args) {
		// 台阶数
		int step = 10000;
		System.out.println("台阶数" + step + "个可走的种类数 " + (new Test1()).countMethod2(step) + "种");

	}
}






 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值