结题思路:假设n个节点存在二叉排序树的个数是G(n),1为根节点,2为根节点,...,n为根节点,当1为根节点时,其左子树节点个数为0,右子树节点个数为n-1,同理当2为根节点时,其左子树节点个数为1,右子树节点为n-2,所以可得G(n) = G(0) * G(n-1)+G(1)* G(n-2)+...+G(n-1)* G(0)

class Solution {
    public int numTrees(int n) {
        if(n==0)return 1;
        int [] ans = new int[n+1];
        ans[0] = 1;
        ans[1] = 1;
        for (int i = 2; i <= n; i++) {
            for(int j = 1 ; j <= i ;j++){
                ans[i] += ans[j-1]*ans[i-j];
            }
        }
        return ans[n];
    }
}

第二种方法也是动态规划,建立dp矩阵,dp[i]代表i个节点能组成多少种二叉搜索树,将dp[0]、dp[1]置为1。然后dp[n]的值为多少呢?

  • 假设以节点值i为根节点(i<=n),那么左子树的节点就为 [公式] ,右子树的节点为 [公式] 。
  • 对于某一个根节点i,假设其左子树的组成方式为left种,右子树的组成方式为right种,那么他们一共可以组成 [公式] 种二叉搜索树。
  • 所以dp[n]就为将左边子树的节点数为分别设置为0个到n-1个时(要有一个根节点),这些情况下左右子树的组成方式之积的和。
    class Solution {
      public int numTrees(int n) {
          int [] dp = new int[n+1];
          dp[0]=1;
          dp[1]=1;
          //计算dp矩阵的值。
          for(int i=2;i<=n;++i)
          {
              //左右子树一一对应,故是乘法。
              for(int l=0;l<=i-1;++l)//左边子树的节点数为0个到i-1个,因为第i个为根节点。
                  dp[i]+=dp[l]*dp[i-l-1];
          }
          return dp[n];
      }
    }