A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.html
Write a data structure CBTInserter
that is initialized with a complete binary tree and supports the following operations:node
CBTInserter(TreeNode root)
initializes the data structure on a given tree with head node root
;CBTInserter.insert(int v)
will insert a TreeNode
into the tree with value node.val = v
so that the tree remains complete, and returns the value of the parent of the inserted TreeNode
;CBTInserter.get_root()
will return the head node of the tree.Example 1:git
Input: inputs = ["CBTInserter","insert","get_root"], inputs = [[[1]],[2],[]] Output: [null,1,[1,2]]
Example 2:github
Input: inputs = ["CBTInserter","insert","insert","get_root"], inputs = [[[1,2,3,4,5,6]],[7],[8],[]] Output: [null,3,4,[1,2,3,4,5,6,7,8]]
Note:數組
1
and 1000
nodes.CBTInserter.insert
is called at most 10000
times per test case.0
and 5000
.
這道題說是讓實現一個徹底二叉樹的插入器的類,以前也作過關於徹底二叉樹的題 Count Complete Tree Nodes。首先須要搞清楚的是徹底二叉樹的定義,即對於一顆二叉樹,假設其深度爲d(d>1)。除了第d層外,其它各層的節點數目均已達最大值,且第d層全部節點從左向右連續地緊密排列,換句話說,徹底二叉樹從根結點到倒數第二層知足完美二叉樹,最後一層能夠不徹底填充,其葉子結點都靠左對齊。因爲插入操做要找到最後一層的第一個空缺的位置,因此很天然的就想到了使用層序遍歷的方法,因爲插入函數返回的是插入位置的父結點,因此在層序遍歷的時候,只要遇到某個結點的左子結點或者右子結點不存在,則跳出循環,則這個殘缺的父結點恰好就在隊列的首位置。那麼在插入函數時,只要取出這個殘缺的父結點,判斷若其左子結點不存在,說明新的結點要鏈接在左子結點上,不然將新的結點鏈接在右子結點上,並把此時的左右子結點都存入隊列中,並將以前的隊首元素移除隊列便可,參見代碼以下:函數
解法一:code
class CBTInserter { public: CBTInserter(TreeNode* root) { tree_root = root; q.push(root); while (!q.empty()) { auto t = q.front(); if (!t->left || !t->right) break; q.push(t->left); q.push(t->right); q.pop(); } } int insert(int v) { TreeNode *node = new TreeNode(v); auto t = q.front(); if (!t->left) t->left = node; else { t->right = node; q.push(t->left); q.push(t->right); q.pop(); } return t->val; } TreeNode* get_root() { return tree_root; } private: TreeNode *tree_root; queue<TreeNode*> q; };
下面這種解法縮短了建樹的時間,可是極大的增長了插入函數的運行時間,由於每插入一個結點,都要從頭開始再遍歷一次,並非很高效,能夠看成一種發散思惟吧,參見代碼以下:htm
解法二:blog
class CBTInserter { public: CBTInserter(TreeNode* root) { tree_root = root; } int insert(int v) { queue<TreeNode*> q{{tree_root}}; TreeNode *node = new TreeNode(v); while (!q.empty()) { auto t = q.front(); q.pop(); if (t->left) q.push(t->left); else { t->left = node; return t->val; } if (t->right) q.push(t->right); else { t->right = node; return t->val; } } return 0; } TreeNode* get_root() { return tree_root; } private: TreeNode *tree_root; };
再來看一種不使用隊列的解法,由於隊列老是要遍歷,比較麻煩,若是使用數組來按層序遍歷的順序保存這個徹底二叉樹的結點,將會變得十分的簡單。並且有個最大的好處是,能夠直接經過座標定位到其父結點的位置,經過 (i-1)/2 來找到父結點,這樣的話就完美的解決了插入函數要求返回父結點的要求,並且經過判斷當前完整二叉樹結點個數的奇偶,能夠得知最後一個結點是在左子結點上仍是右子結點上,這樣就能夠直接將新加入的結點連到到父結點的正確的子結點位置,參見代碼以下:隊列
解法三:
class CBTInserter { public: CBTInserter(TreeNode* root) { tree.push_back(root); for (int i = 0; i < tree.size(); ++i) { if (tree[i]->left) tree.push_back(tree[i]->left); if (tree[i]->right) tree.push_back(tree[i]->right); } } int insert(int v) { TreeNode *node = new TreeNode(v); int n = tree.size(); tree.push_back(node); if (n % 2 == 1) tree[(n - 1) / 2]->left = node; else tree[(n - 1) / 2]->right = node; return tree[(n - 1) / 2]->val; } TreeNode* get_root() { return tree[0]; } private: vector<TreeNode*> tree; };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/919
相似題目:
參考資料:
https://leetcode.com/problems/complete-binary-tree-inserter/