Leetcode --- Unique Binary Search Trees II(Medium) === ## Description Given an integer n, return all the structurally unique BST's (binary search trees), which has exactly n nodes of unique values from 1 to n. Return the answer in any order. **給n表示所有數字1~n,將所有用這些數字所組成的不同構的BST列出來.** ### Example ``` 1 1 2 3 3 \ \ / \ / / 2 3 1 3 1 2 \ / \ / 3 2 2 1 ``` **Input**: n = 3 **Output**: [[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]] ### Constraint * 1 <= n <= 8 ## Solutions * **Method 1: Recursion** 所有不同的組合的解 => root =1,2,...,n都要排列過,所以拆成 Sol(n) = sol(root=1) +sol(root=2) +... + sol(root=n) 再帶入BST特性:若root = i => 左子會有**1~ i-1**的數字做組合,右子會有**i+1~n**的數字做組合,再遞迴. ### Implement code ```java= class Solution { public List<TreeNode> generateTrees(int n) { return helper(1,n); } private List<TreeNode> helper(int st,int ed) { List<TreeNode> res =new ArrayList<>(); if(st>ed) { res.add(null); return res; } for(int i =st ; i<=ed ;i++) { List<TreeNode> left = helper(st,i-1); List<TreeNode> right = helper(i+1,ed); for(TreeNode l : left) for(TreeNode r : right) { TreeNode ans = new TreeNode(i,l,r); res.add(ans); } } return res; } } ``` line 8: 停止條件:當要排列的數字大於root則填null line 17,18:將所有得到的左右子做組合 ### Submission on Leetcode Runtime: **1 ms, faster than 93.80%** of Java online submissions for Unique Binary Search Trees II. Memory Usage: **39.6 MB, less than 61.99%** of Java online submissions for Unique Binary Search Trees II. --- * **Method 2: DP** 觀察n=2,n=3 ``` n=2 1 2 \ / 2 1 n=3 1 1 2 3 3 \ \ / \ / / 2 3 1 3 1 2 \ / \ / 3 2 2 1 ``` 新插入的數字一定大於前一個case,==**所以只會出現在root** , **root.rightChild** , **root.rightChild.rightChild** , **....**== 所以變成 ![tree](https://i.imgur.com/nSheLm6.jpg) ==若插入位置原本有node則此串node變成新node的左子== => ``` Org: 1 \ 2 \ 3 Insert(4)在pos 1 1 \ 4 / 2 \ 3 ``` ### Implement code ```java= class Solution { public List<TreeNode> generateTrees(int n) { List<TreeNode> ans = new ArrayList<>(); if(n==0) { ans.add(null); return ans; } List<TreeNode> preL = generateTrees(n-1); for(TreeNode pre : preL) { for(int i =0;i<n;i++) { TreeNode res = insertcur(pre,i,n); if(res != null) ans.add(res); } } return ans; } private TreeNode detect(TreeNode preT ,int pos) { int i =0; while(i<pos-1) { if(preT ==null) { break; } preT =preT.right ; i++; } return preT; } private TreeNode insertcur(TreeNode pre,int pos,int cur) { TreeNode preT = copyT(pre); TreeNode head =preT; TreeNode curT = new TreeNode(cur); if(pos ==0) { curT.left =preT; return curT; } TreeNode part = detect(preT,pos); if(part ==null) { return null; } if(part.right == null) { part.right = curT; } else { curT.left = part.right; part.right =curT; } return head; } private TreeNode copyT(TreeNode T) { if(T ==null) return null; TreeNode newT = new TreeNode(); newT.val =T.val; newT.left = copyT(T.left); newT.right = copyT(T.right); return newT; } } ``` * function:detect(TreeNode preT ,int pos) 探測第pos位置的右子是否為null,root 為 position 0,若尚未探到目標pos則已為null則此case須被丟棄,直接回傳null. 為了之後好操作少探測一次,之後可以用preT.right來增減樹 * function:insertcur(TreeNode pre,int pos,int cur) 在n-1的解pre中,對第pos位置的右子插入Node(cur) 必須用copyTree來保護,因為一個pre會被操作很多次,把pos=0作為特別解,額外處理,其他部分做detect來看要不要做修正,detect=null時為被丟棄的case * Main 對每一個上一個解,把新node分別嘗試插在root,root.right ..... ### Submission on Leetcode Runtime: **1 ms, faster than 93.76%** of Java online submissions for Unique Binary Search Trees II. Memory Usage: **39.8 MB, less than 31.59%** of Java online submissions for Unique Binary Search Trees II. ###### tags: `Leetcode` `Medium` `DP` `Tree`