> For the complete documentation index, see [llms.txt](https://hao-fu-1.gitbook.io/oj/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hao-fu-1.gitbook.io/oj/binary_tree_and_divide_conquer/binary-search-tree/unique-binary-search-trees-ii.md).

# Unique Binary Search Trees II

<https://leetcode.com/problems/unique-binary-search-trees-ii/description/>

> Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n.
>
> For example,
>
> Given n = 3, your program should return all 5 unique BST's shown below.

## Thoughts

分治的略繁琐应用。利用BST的性质，左子树范围都比给定的数小，右子树范围比给定的数大，假设当前函数返回给定范围的所有BST，那把所有左子树和右子树都组合一遍就是结果。

root可以是范围内的所有节点.

~~还可以用个map存储已经生成过的树的范围以避免重复生成~~

## Code

```
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private List<TreeNode> helper(int start, int end) {
        List<TreeNode> roots = new ArrayList<>();
        if (start > end) {
            return roots;
        }

        if (start == end) {
            roots.add(new TreeNode(start));
            return roots;
        }

        for (int i = start; i <= end; i++) {
            TreeNode root;
            List<TreeNode> lefts = helper(start, i - 1);
            List<TreeNode> rights = helper(i + 1, end);
            for (TreeNode left : lefts) {     
                for (TreeNode right : rights) {
                    root = new TreeNode(i);
                    root.left = left;
                    root.right = right;
                    roots.add(root);
                }
                if (rights.isEmpty()) {
                    root = new TreeNode(i);
                    root.left = left;
                    roots.add(root);
                }
            }
            if (lefts.isEmpty()) {            
                for (TreeNode right : rights) {
                    root = new TreeNode(i);
                    root.right = right;
                    roots.add(root);
                }        
            }
        }

        return roots;
    }

    public List<TreeNode> generateTrees(int n) {
        return helper(1, n);
    }
}
```

## Analysis

Errors:

1. new root(i)位置写错
2. 忘了考虑左右子树为空的情况。
3. 引入了不必要的map

## Ver.2

<https://discuss.leetcode.com/topic/2940/java-solution-with-dp>

顺着它是在DP求Unique Binary Search Tree I 的思路, i为当前节点个数, j为当前root, 它左子树可以有f\[j - 1]种树的形状, 分别就是前面f\[j-1]对应生成的树; 右子树有f\[i - j - 1]种形状, 它们形状和f\[i - j-1]是一样的, 区别在于值, 每个节点相当于f\[i - j -1]的树们的每个节点的值加上j + 1这个offset.

```
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode clone(TreeNode node, int offset) {
        if (node == null) {
            return null;
        }
        TreeNode newNode = new TreeNode(node.val + offset);
        newNode.left = clone(node.left, offset);
        newNode.right = clone(node.right, offset);
        return newNode;
    }

    public List<TreeNode> generateTrees(int n) {
        List<TreeNode>[] result = new List[n + 1];
        result[0] = new ArrayList<TreeNode>();
        if (n == 0) {
            return result[0];
        }

        result[0].add(null);
        for (int i = 1; i <= n; i++) {
            result[i] = new ArrayList<TreeNode>();
            for (int j = 0; j < i; j++) {
                for (TreeNode nodeL : result[j]) {
                    for (TreeNode nodeR : result[i - j - 1]) {
                        TreeNode node = new TreeNode(j + 1);
                        node.left = nodeL;
                        node.right = clone(nodeR, j + 1);
                        result[i].add(node);
                    }
                }
            }
        }

        return result[n];
    }
}
```

## Analysis

时间复杂度应是每个1\~N所对应的卡特兰数之和, Sigma\_i (2i)!/\[(i+1)!i!]
