Unique Binary Search Trees II

題目

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.

Input:

BST的最大值(BST范圍1-n):: Integer

Output:

由1~ n組成的所有BST :: List<TreeNode>

Recursion 解法

Intuition:

這道題吶,其實Recursion的想法很容易想,我們依次遍歷每個數,把這個數當初Root,那么比這個數小的數都當成左子樹,比這個數大的數都當成右子樹。退出Recursion的條件自然是左邊界大于右邊界啦。

Edge Case:

if (n <= 0){
  return new ArrayList<TreeNode>();
}

Code:

public List<TreeNode> UniBST(int n){
  //edge cases
  if (n <= 0){
    return new ArrayList<TreeNode>();
  }
  return helper(1, n);
}

public List<TreeNode> helper(int left, int right){
  List<TreeNode> res = new ArrayList<>();
  if (left > right){
    res.add(null);
    return res;
  }
  
  for (int i = 1; i <= n; i++){
    List<TreeNode> left = helper(left, i - 1);
    List<TreeNode> right = helper(i + 1, right);
    for (TreeNode l: left){
      for (TreeNode r: right){
        TreeNode root = new TreeNode(i);
        root.left = l;
        root.right = r;
        res.add(root);
      }
    }
  }
  return res;
}

DP 解法

但是這道題居然還可以用DP解而且解法比較匪夷所思...
首先,根據DP的本質是當前問題是基于之前的子問題來解決的。那么這道題我們是想建一個擁有n個node的樹,很自然的想到能不能在利用n-1個node的樹。

一步步來哈,左邊的樹好想啊, 1 到 n-1 的數組成的樹肯定每個node的值都比n小啊,那這個樹可以直接拿來安到左邊當做子樹就好。

Tricky的部分在于我們怎么通過n-1個node建成的樹來得出n個node樹的右子樹呢?最明顯的問題就是值不夠大呀。怎么辦?沒有條件創造條件也要上啊( ̄︶ ̄)↗, 我們不是想右邊子樹的值都大于n么?那么就直接在之前已經建好的某個樹所有的node都加n就好了。

還有要注意的一點就是子樹的選擇要確保他們node的個數加1(root)是等于n的。

和所有的DP一樣,我們需要有個DP array, 而因為我們依賴于n-1個node的樹(可能不止一種),那么這個array里面存的就應該是List<TreeNode>,即

List<TreeNode>[] dp = new List<TreeNode>[n + 1];

起始狀態 是0 個node,沒法建樹,那么index為0對應的那個List<TreeNode>里放 null

是不是還是一臉懵逼???沒關系我們跑個??
來看看n = 3的情況吧

n = 1 和 n = 2的情況比較trivial,我們跳過, 假設0 ~ 2 的dp array我們已經填好了,應該是這個樣子滴:

image.png

那么此時我們可以選擇可以作為子樹的的root范圍是0 ~ 2
意義上可以表示為:

image.png

要建一個3個node的樹,假如取一個含0個node的樹作為左子樹 即為dp[0]里存的樹, 新的root的值應該比左子樹最大值大1, 即為1。 右子樹取剩下的node, 即為 3 - 0 - 1 = 2, 也就是dp[2]里存的樹, 但是右子樹我們還要進一步處理讓他比新的root大,那么加offset 1,注意這是dp[2]里已經有兩個樹。最終得到的樹為也有兩種可能:

image.png
image.png

Code:

TC: O(n^4) SC: O(n^2)?

public List<TreeNode>UniqueBST(int n){
  if (n == 0){
    return new ArrayList<TreeNode>(null);
  }
  //initialize
  List<TreeNode>[] dp = new List<TreeNode>[n + 1];
  dp[0].add(null);

  for (int i = 1; i <= n; i++){ //select total number of nodes in a tree
    dp[i] = new ArrayList<>();
    for (int j = 0; j < i; j++){ //select number of nodes in left subtree
      for (TreeNode l: dp[i]){
        for (TreeNode r: dp[i - 1 - j]){ //select number of nodes in right subtree
          TreeNode newRoot = new TreeNode(j + 1);
           newRoot.left = l;
           newRoot.right = addOffset(r, j + 1);
           dp[i].add(newRoot);
        }
      }
    }
  }
  return dp[n];
}

public TreeNode addOffset(TreeNode root, int offset){
  if (root == null){
    return null;
  }
  TreeNode res = new TreeNode(root.val + offset);
  res.left = addOffset(root.left, offset);
  res.right = addOffset(root.right, offset);
  return res;
}

Reference

https://discuss.leetcode.com/topic/2940/java-solution-with-dp
https://leetcode.com/problems/unique-binary-search-trees-ii/description/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容