/* 这道题的关键是:动态表尽量的选取,知道二叉搜索树中左子树的点都比根节点小,右子树的点都比根节点大 所以当i为根节点,左子树有i-1个点,右子树有n-i个点,左右子树就可以开始递归构建,过程和一开始的过程是一样的, 而左右子树的特征中可以知道的就是点的个数,所以用点的个数作为动态变量就很好。 这样就给我们提供了一个思路:动态规划和树结合的题,由于子问题就是左右树,所以动态变量的选取基本就是考虑题目给出的信息 中,可以从根节点得到左右子树的哪些特征,用这个特征作为动态变量。 二叉搜索树中,都是左子树的点小于根节点,右子树的点大于根节点,对于所有子树都是这样。 用dp[i]表示有i个数的时候能组成多少树 dp[i] = dp[0]*dp[i-1]+ ...+ dp[i-1]*dp[0] 等号右边分别代表1到i分别是根节点的情况 */ int[] dp = new int[n+1]; dp[0] = 1;//当没有节点时,就只有一种情况 for (int i = 1; i < n+1; i++) { for (int j = 0; j < i; j++) { dp[i] += dp[j] * dp[i-j-1]; } } return dp[n];
1 public List<TreeNode> generateTrees(int n) { 2 /* 3 从i到n依次选取做为根节点,生成一棵树.根节点为i的这个过程我们叫做function(i),则function(i)中左子树就是从1到i-1的 4 生成过程,右子树就是从i+1到n的过程,递归function就行,然后对左右子树就行全匹配就行 5 */ 6 if (n < 1) 7 return new ArrayList<TreeNode>(); 8 return build(1, n); 9 } 10 11 public List<TreeNode> build(int start, int end) { 12 List<TreeNode> res = new ArrayList<>(); 13 if (start > end) 14 { 15 res.add(null); 16 return res; 17 } 18 for (int i = start; i <= end; i++) { 19 List<TreeNode> left = build(start, i - 1); 20 List<TreeNode> right = build(i + 1, end); 21 22 for (TreeNode lt : 23 left) { 24 for (TreeNode rt : 25 right) { 26 //由于每次组合都形成一个新的树,所以新建树应该是在这里 27 TreeNode root = new TreeNode(i); 28 root.left = lt; 29 root.right = rt; 30 //注意添加的位置,每组合一个左右子树就会形成一种情况 31 res.add(root); 32 } 33 } 34 35 } 36 return res; 37 }