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.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

是第96题的延伸,要求出所有可能性。

 

 

刚开始写了一个回溯法,但是由于没有办法在TreeNode中重写equals,导致需要重写的东西很多(主要这样做的话,一个一个添加TreeNode。会出现重复的情况),也就导致了时间很长。一百多ms。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    List list = new ArrayList<TreeNode>();
    public List<TreeNode> generateTrees(int n) {
        
        if( n == 0)
            return list;
        int[] pos = new int[n];
        for( int i = 0;i<n;i++){
            pos[i] = 1;
            TreeNode root = new TreeNode(i+1);
            getResult(root,pos);
            pos[i] = 0;
        }
        return list;
    }

    public void getResult(TreeNode root,int[] pos){

        int flag = 0;
        for( int i = 0;i<pos.length;i++){
            if( pos[i] == 0){
                addNode(root,i);
                pos[i] = 1;
                getResult(root,pos);
                delNote(root,i);
                pos[i] = 0;
                flag = 1;
            }
        }
        if( flag == 0){
            TreeNode ans = getAns(root);
            if( !isExist(ans) )
                list.add(ans);
        }
            

    }
    public boolean isExist(TreeNode ans){
        int size = list.size();
        for( int i = 0;i<size;i++){
            if( isSame((TreeNode)list.get(i),ans) )
                return true;
        }
        return false;
              
    }
    public boolean isSame(TreeNode node1,TreeNode node2){
        if( node1.val != node2.val)
            return false;
        if( node1.left != null && node2.left != null){
            if( !isSame(node1.left,node2.left) )
                return false;
        }else if( node1.left == null && node2.left == null)
            ;
        else 
            return false;
        if( node1.right != null && node2.right != null){
            if( !isSame(node1.right,node2.right) )
                return false;
        }else if( node1.right == null && node2.right == null )
            ;
        else 
            return false;
        return true;
    }
    
    public TreeNode getAns(TreeNode root){
        
        TreeNode ans = new TreeNode(root.val);
        if( root.left != null )
            ans.left = getAns(root.left);
        if( root.right != null)
            ans.right = getAns(root.right);
        return ans;        
    }
    
    
    
    public void addNode(TreeNode root,int i ){
        while( true){
            if( i+1 > root.val ){
                if( root.right == null){
                    root.right = new TreeNode(i+1);
                    return ;
                }else
                    root = root.right;
            }else{
                if( root.left == null){
                    root.left = new TreeNode(i+1);
                    return ;
                }else
                    root = root.left;
            }
        }
    }
    public void delNote(TreeNode root,int i){
        while( true){
            if( i+1 > root.val ){
                if( i+1 == root.right.val ){
                    root.right = null;
                    return ;
                }else
                    root = root.right;
            }else{
                if( i+1 == root.left.val ){
                    root.left = null;
                    return ;
                }else
                    root = root.left;
            }
        }
    }
    
}

然后看了网上的解答,有两个我认为还不错,一个是根据树的结构来回溯,效率很高,不会出现重复,

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<TreeNode> generateTrees(int n) {
        
        if(n == 0) {
            return new ArrayList<TreeNode>();
        }
        
        return gen(1, n);
    }
    
    List<TreeNode> gen(int start, int end) {
        ArrayList<TreeNode> heads = new ArrayList<TreeNode>();
        if(start > end) {
            heads.add(null);
            return heads;
        }
        
        for(int i = start; i <= end; i++) {
            
            List<TreeNode> lefts = gen(start, i - 1);
            List<TreeNode> rights = gen(i + 1, end);
            
            for(TreeNode left : lefts) {
                for(TreeNode right : rights) {
                    TreeNode head = new TreeNode(i);
                    head.left = left;
                    head.right = right;
                    heads.add(head);
                }
            }
        }
        
        return heads;
        
    }
}

 还有一种动态规划其实也就是第二种方法的改良。

public static 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 len = 1; len <= n; len++) {
        result[len] = new ArrayList<TreeNode>();
        for (int j = 0; j < len; j++) {
            for (TreeNode nodeL : result[j]) {
                for (TreeNode nodeR : result[len - j - 1]) {
                    TreeNode node = new TreeNode(j + 1);
                    node.left = nodeL;
                    node.right = clone(nodeR, j + 1);
                    result[len].add(node);
                }
            }
        }
    }
    return result[n];
}

private static TreeNode clone(TreeNode n, int offset) {
    if (n == null) {
        return null;
    }
    TreeNode node = new TreeNode(n.val + offset);
    node.left = clone(n.left, offset);
    node.right = clone(n.right, offset);
    return node;
}