动态规划专题之--- Unique Binary Search Trees

    • 1.分解子问题
    • 2.确定状态
    • 3.确定初始状态
    • 4.确定状态转移方程

题目链接
参考博文

表示根本不知道什么是卡特兰数,百度的截图
image_1bdeqri3b18kp29b1npl1btol759.png-13kB

根据动态规划解题步骤慢慢分析

1.分解子问题

根据题意分析,二叉搜索树不同原因在于。一个数列中的所有元素都可以成为祖先。
于是第一个子问题是每个数都可以作为祖先。我们可以遍历数列。

然后确定一个数为祖先后,剩下n-1个数先分为两拨,而这两拨如何分?左子树节点数从0开始一直到某个临界值时,这样过一遍就是完美了。

于是左子树的子树又可以根据这样的递推关系继续往下面分。

当祖先(根为数值为i时),左子树最大的数为i-1。于是左子树的元素个数可以从0增加到i-1。而右子树的节点个数也可以依次增多。

image_1bdescqft3uo1t8v60r8ad7e9.png-17.9kB

这里的n=3,不是说的根节点数字为3,而是说的当节点数为3的时候

2.确定状态

dp[i]=j 表示当有i的节点时,BST的种类数目。

3.确定初始状态

dp[0]=1; 没有节点只有一种情况,空树
dp[1]=dp[0]*dp[0]=1; 只有一个节点也是只有一种情况

4.确定状态转移方程

int i;
 for(int j=0;j1];
 }
   
   
   
   
  • 1
  • 2
  • 3
  • 4

模拟一下输入3的情况

i
i=1 dp[1]=dp[0]∗dp[0]” role=”presentation” style=”position: relative;”>dp[1]=dp[0]dp[0]dp[1]=dp[0]∗dp[0]
i=2 dp[2]=dp[1]∗dp[0]” role=”presentation” style=”position: relative;”>dp[2]=dp[1]dp[0]dp[2]=dp[1]∗dp[0] dp[2]=dp[0]∗dp[1]” role=”presentation” style=”position: relative;”>dp[2]=dp[0]dp[1]dp[2]=dp[0]∗dp[1]
i=3 dp[3]=dp[2]∗dp[0]” role=”presentation” style=”position: relative;”>dp[3]=dp[2]dp[0]dp[3]=dp[2]∗dp[0] dp[3]=dp[1]∗dp[1]” role=”presentation” style=”position: relative;”>dp[3]=dp[1]dp[1]dp[3]=dp[1]∗dp[1] dp[3]=dp[0]∗dp[2]” role=”presentation” style=”position: relative;”>dp[3]=dp[0]dp[2]dp[3]=dp[0]∗dp[2]

1. i=1 表示只有一个节点的情况
2. i=2 表示两个节点的情况,这个时候就可以利用case1中计算出来的结果dp[1]了。
3. i=3 表示三个节点的情况,这个时候就可以利用case2中计算出来的结果了。

对应i=3的时候
image_1bdesri85133m1l1811i21tlp16rm.png-109.7kB

public class Solution{
    public int numTrees(int n){
        if(n==0||n==1){
            return 1;
        }
        int []dp=new int[n+1];
        //每个数都可以做根节点,相当于有这么多个节点时
        for(int i=1;i<=n;i++){

            //i为根节点时,左子树从0开始增加
            for(int j=0;j1];
            }
        }
        return dp[n];
    }

}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

image_1bdetejv91u6a1a6k3fo1vo2q9113.png-20.9kB




你可能感兴趣的:(练习题)