從物理學到計算機,再到硬件,再到人工智能!
藍橋杯備賽 (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);
}
}