111. 爬楼梯

从物理学到计算机,再到硬件,再到人工智能!
蓝桥杯备赛 (LintCode上刷的第七题)

问题描述

假设你正在爬楼梯,需要n步你才能到达顶部。但每次你只能爬一步或者两步,你能有多少种不同的方法爬到楼顶部?

样例输出

比如n=3,1+1+1=1+2=2+1=3,共有3种不同的方法

问题分析

这道题参考了换钱的方法数的思想。不同的是,此题中1 + 2 = 2+ 1是两种方式,于是我在此基础上加入了组合,就完美地解决了问题。

JAVA实现代码

package DP;

public class Upstairs111_1113 {

	/**
	 * 通过arr数组中不同步数的选择到达aim
	 * @param arr 可供选择步数
	 * @param aim 要爬的楼梯数
	 * @return
	 */
	public static int upstairs(int[] arr, int aim) {
		//判断输入参数的有效性
		if (arr == null || arr.length == 0 || aim < 0) {
			return 0;
		}
		//创建一个数组,dp[i][j]表示arr[0...i]组成j有多少种方式
		int dp[][] = new int[arr.length][aim + 1];
		//组成0的方式只有一种,就是不使用arr中的任何值
		for (int i = 0; i < arr.length; i ++) {
			dp[i][0] = 1;
		}
		//只使用arr[0]时,只能组成其倍数的值,且组成方式只有一种
		for (int i = 0; arr[0] * i <= aim; i ++) {
			dp[0][arr[0] * i] = 1;
		}
		// 定义一个变量记录有多少种方法
		int num = 0;
		//使用arr中不同值
		for (int i = 1; i < arr.length; i ++) {
			//遍历所有小于aim的值的组成情况
			for (int j = 1; j <= aim; j ++) {
				num = 0;
				//当使用k次arr[i]时,j的所有组成方式
				for (int k = 0; j - arr[i] * k >= 0; k ++) {
					//因为存在顺序,所以k次的排列位置也会产生不同的排列方式,采用组合的方式
					num += dp[i - 1][j - arr[i] * k] + combination(k, (j - arr[i] * k) / arr[i -1] + k) - 1;
				}
				dp[i][j] = num;
			}
		}
//		for (int i = 0; i < dp.length; i++) {
//			for (int j = 0; j < dp[0].length; j++) {
//				System.out.print(dp[i][j] + " ");
//			}
//			System.out.println();
//		}
		return dp[arr.length - 1][aim];
	}

	/**
	 * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1
	 * @param n
	 * @return
	 */
	private static long factorial(int n) {
		long sum = 1;
		while (n > 0) {
			sum = sum * n--;
		}
		return sum;
	}

	/**
	 * 组合计算公式C<sup>m</sup><sub>n</sub> = n! / (m! * (n - m)!)
	 * @param m
	 * @param n
	 * @return
	 */
	public static long combination(int m, int n) {
		return m <= n ? factorial(n) / (factorial(m) * factorial((n - m))) : 0;
	}
	
	public static void main(String[] args) {
		int[] arr = new int[2];
		arr[0] = 1;
		arr[1] = 2;
		int n = 3;
		int res = upstairs(arr, n);
		System.out.println(res);
	}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值