import java.math.BigInteger;
import java.util.*;
/**
* NC310 不同的二叉搜索树(一)
* @author d3y1
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @return int整型
*/
public int BSTCount (int n) {
return solution1(n);
// return solution2(n);
// return solution3(n);
// return (int) solution4(n);
}
/**
* 动态规划
*
* 画图举例子找规律:
*
* dp[i][j]表示总节点数为i且以节点j为根节点时构成互不相同二叉搜索树的方法数
* C[i]表示总节点数为i时构成互不相同二叉搜索树的方法数
*
* // 固定根节点j 左子树还有j-1个节点(方法数为C[j-1]) 右子树还有i-j个节点(方法数为C[i-j])
* dp[i][j] = C[j-1] * C[i-j]
* // 分别以各个节点为根节点
* C[i] = dp[i][1] + dp[i][2] + ... + dp[i][i-1] + dp[i][i] , 2<=i<=n && 1<=j<=i
* = C[1-1] * C[i-1] + C[2-1] * C[i-2] + ... + C[(i-1)-1] * C[i-(i-1)] + C[i-1] * C[i-i]
* = C[0] * C[i-1] + C[1] * C[i-2] + ... + C[i-2] * C[1] + C[i-1] * C[0]
*
* @param n
* @return
*/
private int solution1(int n){
int[] C = new int[n+1];
int[][] dp = new int[n+1][n+1];
C[0] = 1;
C[1] = 1;
for(int i=2; i<=n; i++){
for(int j=1; j<=i; j++){
dp[i][j] = C[j-1] * C[i-j];
C[i] += dp[i][j];
}
}
return C[n];
}
/**
* 动态规划: 简化
*
* 画图举例子找规律:
*
* C[i]表示总节点数为i时构成互不相同二叉搜索树的方法数
* C[i] = C[0] * C[i-1] + C[1] * C[i-2] + ... + C[i-2] * C[1] + C[i-1] * C[0] , 2<=i<=n && 1<=j<=i
*
* @param n
* @return
*/
private int solution2(int n){
int[] C = new int[n+1];
C[0] = 1;
C[1] = 1;
for(int i=2; i<=n; i++){
for(int j=1; j<=i; j++){
C[i] += C[j-1] * C[i-j];
}
}
return C[n];
}
/**
* 数学法
*
* 画图举例子找规律:
*
* C[i]表示总节点数为i时构成互不相同二叉搜索树的方法数(C[0] = C[1] = 1)
* C[i] = C[0] * C[i-1] + C[1] * C[i-2] + ... + C[i-2] * C[1] + C[i-1] * C[0] , 2<=i<=n && 1<=j<=i
*
* 可见:
* C[0] = 1
* C[1] = 1
* C[2] = 2
* C[3] = 5
* C[4] = 14
* C[5] = 42
* C[6] = 132
* ...
*
* 以上为卡塔兰数
* C[n] = C(n) = (2n)! / ((n+1)!n!)
*
* @param n
* @return
*/
private int solution3(int n){
return C(n).intValue();
}
/**
* C(n)
* @param n
* @return
*/
private BigInteger C(int n){
BigInteger up = new BigInteger("1");
BigInteger down = new BigInteger("1");
for(int i=1; i<=n; i++){
if(i < n){
up = up.multiply(BigInteger.valueOf(n+1+i));
}
down = down.multiply(BigInteger.valueOf(i));
}
return up.divide(down);
}
/**
* 数学法
*
* 画图举例子找规律:
*
* C[i]表示总节点数为i时构成互不相同二叉搜索树的方法数(C[0] = C[1] = 1)
* C[i] = C[0] * C[i-1] + C[1] * C[i-2] + ... + C[i-2] * C[1] + C[i-1] * C[0] , 2<=i<=n && 1<=j<=i
*
* 可见:
* C[0] = 1
* C[1] = 1
* C[2] = 2
* C[3] = 5
* C[4] = 14
* C[5] = 42
* C[6] = 132
* ...
*
* 以上为卡塔兰数
* C[n] = C(n) = C(n-1)*(4n-2)/(n+1)
*
* @param n
* @return
*/
private long solution4(int n){
long[] C = new long[n+1];
C[0] = 1L;
for(int i=1; i<=n; i++){
C[i] = C[i-1]*(4*i-2)/(i+1);
}
return C[n];
}
}