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.

Write a data structure CBTInserter that is initialized with a complete binary tree and supports the following operations:

  • 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:

Input: inputs = ["CBTInserter","insert","get_root"], inputs = [[[1]],[2],[]]
Output: [null,1,[1,2]]

Example 2:

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. The initial given tree is complete and contains between 1 and 1000 nodes.
  2. CBTInserter.insert is called at most 10000 times per test case.
  3. Every value of a given or inserted node is between 0 and 5000.

这道题说是让实现一个完全二叉树的插入器的类,之前也做过关于完全二叉树的题 [Count Complete Tree Nodes](http://www.cnblogs.com/grandyang/p/4567827.html)。首先需要搞清楚的是完全二叉树的定义,即对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,换句话说,完全二叉树从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐。由于插入操作要找到最后一层的第一个空缺的位置,所以很自然的就想到了使用层序遍历的方法,由于插入函数返回的是插入位置的父结点,所以在层序遍历的时候,只要遇到某个结点的左子结点或者右子结点不存在,则跳出循环,则这个残缺的父结点刚好就在队列的首位置。那么在插入函数时,只要取出这个残缺的父结点,判断若其左子结点不存在,说明新的结点要连接在左子结点上,否则将新的结点连接在右子结点上,并把此时的左右子结点都存入队列中,并将之前的队首元素移除队列即可,参见代码如下:


解法一:

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;
};

下面这种解法缩短了建树的时间,但是极大的增加了插入函数的运行时间,因为每插入一个结点,都要从头开始再遍历一次,并不是很高效,可以当作一种发散思维吧,参见代码如下:


解法二:

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

类似题目:

Count Complete Tree Nodes

参考资料:

https://leetcode.com/problems/complete-binary-tree-inserter/

https://leetcode.com/problems/complete-binary-tree-inserter/discuss/178424/C%2B%2BJavaPython-O(1)-Insert

https://leetcode.com/problems/complete-binary-tree-inserter/discuss/178528/Java-Solution%3A-O(1)-Insert-VS.-O(1)-Pre-process-Trade-Off

https://leetcode.com/problems/complete-binary-tree-inserter/discuss/178427/Java-BFS-straightforward-code-two-methods-Initialization-and-insert-time-O(1)-respectively.

[LeetCode All in One 题目讲解汇总(持续更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)

[LeetCode] 919. Complete Binary Tree Inserter 完全二叉树插入器的更多相关文章

  1. LeetCode 919. Complete Binary Tree Inserter

    原题链接在这里:https://leetcode.com/problems/complete-binary-tree-inserter/ 题目: A complete binary tree is a ...

  2. 【LeetCode】919. Complete Binary Tree Inserter 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址: https://leetcode. ...

  3. leetcode_919. Complete Binary Tree Inserter_完全二叉树插入

    https://leetcode.com/problems/complete-binary-tree-inserter/ 给出树节点的定义和完全二叉树插入器类的定义,为这个类补全功能.完全二叉树的定义 ...

  4. [Swift]LeetCode919. 完全二叉树插入器 | Complete Binary Tree Inserter

    A complete binary tree is a binary tree in which every level, except possibly the last, is completel ...

  5. PAT 1110 Complete Binary Tree[判断完全二叉树]

    1110 Complete Binary Tree(25 分) Given a tree, you are supposed to tell if it is a complete binary tr ...

  6. leetcode_919. Complete Binary Tree Inserter

    https://leetcode.com/problems/complete-binary-tree-inserter/ 设计一个CBTInserter,使用给定完全二叉树初始化.三个功能; CBTI ...

  7. PAT A1110 Complete Binary Tree (25 分)——完全二叉树,字符串转数字

    Given a tree, you are supposed to tell if it is a complete binary tree. Input Specification: Each in ...

  8. [二叉树建树&完全二叉树判断] 1110. Complete Binary Tree (25)

    1110. Complete Binary Tree (25) Given a tree, you are supposed to tell if it is a complete binary tr ...

  9. PAT甲级——1110 Complete Binary Tree (完全二叉树)

    此文章同步发布在CSDN上:https://blog.csdn.net/weixin_44385565/article/details/90317830   1110 Complete Binary ...

随机推荐

  1. webpack打包教程(一)常用loader详解

    1.打包图片 // { // test: /\.(png|jpe?g|gif)$/i, // use: [{ // loader: 'file-loader', // options: { // na ...

  2. 1+x 证书 Web 前端开发 CSS3 专项练习

    官方QQ群 1+x 证书 Web 前端开发 CSS3 专项练习 http://blog.zh66.club/index.php/archives/196/

  3. eclipse查看一个方法被谁调用的快捷键

    我们知道,在idea中是可以通过[ctrl+鼠标左键单击]去跳到方法调用方去的,但是在eclipse中却是不行的. 三种快捷键方式 这里列出在eclipse中查看一个方法被谁调用的三种方式(快捷键). ...

  4. C# NuGet常用命令

    命令执行位置:工具=〉Nuget包管理器=〉程序包管理器控制台 一.安装 1.安装指定版本类库install-package <程序包名> -version <版本号> 2.安 ...

  5. Winforn中使用FastReport实现点击导出按钮PDF预览并弹出另存为对话框

    场景 FastReport安装包下载.安装.去除使用限制以及工具箱中添加控件: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...

  6. Java学习——内存机制

    Java学习——内存机制 摘要:本文主要介绍了Java的内存机制. 部分内容来自以下博客: https://www.cnblogs.com/xrq730/p/4827590.html https:// ...

  7. 二十:职责链模式详解(类似于spring的hangler处理请求)

    定义:为了避免请求的发送者和接收者之间的耦合关系,使多个接受对象都有机会处理请求.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. “看这个定义,就是将一堆可以处理请求的对象连 ...

  8. 原生JavaScript HTML DOM Style 对象参考

    Style 对象属性 可以在Style对象上使用以下属性: “CSS”列指示定义属性的CSS版本(CSS1,CSS2或CSS3). 属性 描述 CSS alignContent 当项目不使用所有可用空 ...

  9. vue国际化问题i18n为null

    1.vue的国际化关于使用请看这位大佬的文章https://segmentfault.com/a/1190000015008808 2.this指向问题https://segmentfault.com ...

  10. 关于oracle PL/SQL存储过程 PLS-00905 object is invalid,statement ignored问题的解决

    昨天在学习oracle存储过程的时候,写了一个存储过程的demo,语句是这样的: )) AS psssal TESTDELETE.TESTID%TYPE; BEGIN SELECT TESTID IN ...