[LeetCode] 894. All Possible Full Binary Trees 全部可能的滿二叉樹



full binary tree is a binary tree where each node has exactly 0 or 2 children.html

Return a list of all possible full binary trees with Nnodes.  Each element of the answer is the root node of one possible tree.node

Each node of each tree in the answer must have node.val = 0.git

You may return the final list of trees in any order.github

Example 1:數組

Input: 7
Output: [[0,0,0,null,null,0,0,null,null,0,0],[0,0,0,null,null,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,null,null,null,null,0,0],[0,0,0,0,0,null,null,0,0]]
Explanation:

Note:函數

  • 1 <= N <= 20



這道題給了一個數字N,讓咱們生成全部包含N個結點的滿二叉樹。所謂的滿二叉樹,就是每一個結點必定會有0個或2兩個子結點,換句話說,子結點必須成對出現,注意跟徹底二叉樹區分。如今咱們有N個結點可使用,若咱們仔細觀察,能夠發現,全部的滿二叉樹的結點總數都是奇數,因此只要當N爲偶數的時候,必定返回的是空數組,這個能夠看成一個剪枝放在開頭。下面咱們就來考慮當N是奇數時,如何生成不一樣的滿二叉樹。先從最簡單的開始,當 N=1 時,就只有一個根結點,當 N=3 時,也只有一種狀況,根結點和左右子結點,當 N=5 時,就有以下兩種狀況:code

0
   / \
  0   0
 / \
0   0


    0
   / \
  0   0
     / \
    0   0

咱們能夠看出來就是在 N=3 的狀況下再多加兩個結點,這兩個結點能夠都在左子結點下,或者都在右子結點下。可是當 N=7 的時候就比較 tricky 了,也能夠看做是在 N=5 的狀況下生成的,咱們能夠把多餘出來的兩個結點分別加到上面兩棵樹的任意一個葉結點下方,但可能你會有疑問,上面的兩棵樹各自都有三個葉結點,每一個都加的話,不就應該有6種狀況了麼,其實只有5種,由於其中有兩種狀況是重合的,即在第一棵樹的最右葉結點下添加,跟在第二棵樹的最左葉結點下添加後獲得的徹底二叉樹是同樣的,因此總共只有5種組合。htm

講到這裏,身爲讀者的你可能仍是比較迷茫,到底該如何用代碼來生成,咱們再換一種思惟方式,若總共有N個結點能夠分配,那麼除去根結點,左右子樹一共能夠分配 N-1 個結點,因爲N必定是奇數,那麼 N-1 必定就是偶數,因此左右子樹須要共同來分配這 N-1 個結點。又由於滿二叉樹的子樹也必須是滿二叉樹,因此每一個子樹的結點總數也應該是奇數,因爲 N-1 是偶數,因此這 N-1 個結點不可能所有給其中的一個子樹,即左右子樹至少有一個結點,那麼實際上就是把 N-1 這個偶數拆分紅任意兩個奇數之和,好比p和q,知足 p+q = N-1,且p,q均爲奇數,而後對其分別對p和q調用遞歸函數,獲得兩個數組,數組裏面的就是全部可能狀況的左右子樹的根結點。以後要作的就是從這兩個數組中任意取兩個結點,加到一個新建的 cur 結點的左右子結點上,而後將 cur 結點存入結果 res 中。這種處理方法跟以前的那兩道題 Unique Binary Search Trees IIDifferent Ways to Add Parentheses 如出一轍,若你們眼睛夠尖的話,能夠看出來這其實也是 卡塔蘭數 Catalan Numbe,參見代碼以下:blog



解法一:遞歸

class Solution {
public:
    vector<TreeNode*> allPossibleFBT(int N) {
        if (N % 2 == 0) return {};
        if (N == 1) return {new TreeNode(0)};
        vector<TreeNode*> res;
        for (int i = 1; i < N; i += 2) {
            vector<TreeNode*> left = allPossibleFBT(i), right = allPossibleFBT(N - i - 1);
            for (auto a : left) {
                for (auto b : right) {
                    TreeNode *cur = new TreeNode(0);
                    cur->left = a;
                    cur->right = b;
                    res.push_back(cur);
                }
            }
        }
        return res;
    }
};



咱們能夠經過使用一個 HashMap 來避免重複計算,從而提高運算速度,創建每一個值跟其對應的滿二叉樹的根結點數組之間的映射,那麼在遞歸函數中,斷定完了偶數跟1的狀況後,就看當前N值是否已經計算過了,是的話,直接從 HashMap 中取數組,不然就進行和上面同樣的運算,最後在返回前要將結果存入 HashMap 中,參見代碼以下:



解法二:

class Solution {
public:
    unordered_map<int, vector<TreeNode*>> m;
    vector<TreeNode*> allPossibleFBT(int N) {
        if (N % 2 == 0) return {};
        if (N == 1) return {new TreeNode(0)};
        if (m.count(N)) return m[N];
        vector<TreeNode*> res;
        for (int i = 1; i < N; i += 2) {
            vector<TreeNode*> left = allPossibleFBT(i), right = allPossibleFBT(N - i - 1);
            for (auto a : left) {
                for (auto b : right) {
                    TreeNode *cur = new TreeNode(0);
                    cur->left = a;
                    cur->right = b;
                    res.push_back(cur);
                }
            }
        }
        return m[N] = res;
    }
};



Github 同步地址:

https://github.com/grandyang/leetcode/issues/894



相似題目:

Unique Binary Search Trees II

Different Ways to Add Parentheses



參考資料:

https://leetcode.com/problems/all-possible-full-binary-trees/



LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索