leetcode筆記——95不同的二叉搜索樹Ⅱ

題目:

給定一個整數 n,生成所有由 1 ... n 爲節點所組成的二叉搜索樹

示例:

輸入: 3
輸出:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
解釋:
以上的輸出對應以下 5 種不同結構的二叉搜索樹:

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

思路:在網上找的大神的代碼。原文鏈接:https://blog.csdn.net/onedeveloper/article/details/80169460。

參考了文章https://blog.csdn.net/happyaaaaaaaaaaa/article/details/51635367

今天這個題是真的理解不了。。。。遞歸和二叉樹,還有這個兩層的循環不懂。。。先把其他大神的思路放在這裏。看不懂

1. 每一次都在一個範圍內隨機選取一個結點作爲根。
2. 每選取一個結點作爲根,就把樹切分成左右兩個子樹,直至該結點左右子樹爲空。

大致思路如上,可以看出這也是一個可以劃分成子問題求解的題目,所以考點是動態規劃
但具體對於本題來說,採取的是自底向上的求解過程。
1. 選出根結點後應該先分別求解該根的左右子樹集合,也就是根的左子樹有若干種,它們組成左子樹集合,根的右子樹有若干種,它們組成右子樹集合。
2. 然後將左右子樹相互配對,每一個左子樹都與所有右子樹匹配,每一個右子樹都與所有的左子樹匹配。然後將兩個子樹插在根結點上。
3. 最後,把根結點放入鏈表中。
(原文:https://blog.csdn.net/ChilseaSai/article/details/50083201)

 

代碼:

這個代碼我有點看不懂。。。。。。也是用了遞歸的思想

class Solution {
    public List<TreeNode> generateTrees(int n) {
        if (n < 1) return new ArrayList<>();
        //利用一個輔助數組保存中間的值,避免重複求取,但是也會導致有些子樹的結點是公共的
        List[][] dp = new List[n + 2][n + 2];
        return generateTrees(1, n,dp);
    }
    private List<TreeNode> generateTrees(int start, int end, List[][] dp) {
        List<TreeNode> res = new ArrayList<>();
        if (end < start) {
            res.add(null);
            return res;
        }
        for (int i = start; i <= end; i++) {
            List<TreeNode> list1 = dp[start][i - 1];
            if (list1 == null) {
                //遞歸,並將結果保存下來
                list1 = generateTrees(start, i - 1, dp);
                dp[start][i - 1] = list1;
            } //(start,i-1)爲左子樹,遍歷不同的左子樹組合
            for (TreeNode left : list1) {
                List<TreeNode> list2 = dp[i + 1][end];//當 i = n 時,就需要求 dp[n+1][end] 的值
                if (list2 == null) {
                    //遞歸,並將結果保存下來
                    list2 = generateTrees(i + 1, end, dp);
                    dp[i + 1][end] = list2;
                } //(i+1,end)爲右子樹,遍歷不同的右子樹組合
                for (TreeNode right : list2) {
                    TreeNode root = new TreeNode(i);
                    root.left = left;
                    root.right = right;
                    res.add(root);
                }
            }
        }
        return res;
    }

}

以下的代碼是另外的一種思路:

我能稍微理解下面這個的思路,就是使用遞歸調用,確定一個根節點,然後在遞歸求解出相應的左子樹和右子樹的各種情況,接着將左右子樹一一配對。但是這個題是怎麼和動態規劃有關係的?主要還是用到遞歸的思想

public class Solution {
    public List<TreeNode> generateTrees(int n) {
        if(n <= 0) return new ArrayList<>();
        return greateSubTree(1, n);
    }
    private List<TreeNode> greateSubTree(int start, int end) {
        List<TreeNode> res = new ArrayList<>();
        if(end < start) {
            res.add(null);
            return res;

        }
        for(int i = start; i <= end; i++) {
            for(TreeNode l : greateSubTree(start, i-1)) {  //
                for(TreeNode r : greateSubTree(i+1, end)) {
                    TreeNode root = new TreeNode(i);
                    root.left = l;
                    root.right = r;
                    res.add(root);
                }
            }
        }
        return res;
    }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章