从物理学到计算机,再到硬件,再到人工智能!
蓝桥杯备赛 (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);
}
}