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/