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. Javal连载4-注释&class与public class区别

    一.Java注释 1.作用:不会编译倒.class文件之中:增强可读性 2.分类: (1)单行注释(只注释当前行):// (2)多行注释: /* 注释 注释 注释 */ (3)javadoc注释 /* ...

  2. Apache Maven 3.6.3配置安装

    1.maven 3.5 下载地址:http://maven.apache.org/download.cgi 2.下载了解压到 3.配置环境变量 4.测试看是否安装成功 5.maven配置(全局配置,用 ...

  3. 【shell脚本】通过位置变量创建Linux账户及密码===addUser.sh

    通过位置变量创建Linux账户及密码 脚本内容 [root@VM_0_10_centos shellScript]# vi addUser.sh #!/bin/bash # 通过位置变量创建系统账户及 ...

  4. Docker安装使用以及mlsql的docker安装使用说明

    1.检查内核版本,必须是3.10及以上 uname -r 2.安装 yum -y install docker #1.启动   docker systemctl start docker #1.1.验 ...

  5. Linux SELinux 使用操作

    Linux SELinux 使用操作 # 修改 SELinux 启动模式.临时生效 命令:setenforce [0|1] 0:转成 permissive 宽容模式: 1:转成 Enforcing 强 ...

  6. 深入浅出《设计模式》之简单工厂模式(C++)

    前言 模式介绍 简单工厂模式其实并不属于GoF23(23种设计模式),更类似工厂模式的一种变型.其定义是可以根据参数的不同返回不同类的实例.简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实 ...

  7. VS2010 报错该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失

    尤其代码是从linux平台复制过来: 报错如图: 更有甚者基本函数都报错: 当下检查发现if else break case等基本函数并无问题时,报错行数明显不一致等一定要注意文档编码格式, 最简单的 ...

  8. 最新版windows安装支持输入shell命令的工具cygwin教程

    首先去官网下载自己对应系统32位或64位系统版本安装包:https://cygwin.com/install.html 下载好后按提示一步一步安装,直到这一步: 初次安装,这里是空的,没有下载的镜像链 ...

  9. flink 批量梯度下降算法线性回归参数求解(Linear Regression with BGD(batch gradient descent) )

    1.线性回归 假设线性函数如下: 假设我们有10个样本x1,y1),(x2,y2).....(x10,y10),求解目标就是根据多个样本求解theta0和theta1的最优值. 什么样的θ最好的呢?最 ...

  10. [PHP] 广度优先搜索匹配网站所有链接

    <?php define('PRE_DOMAIN','www'); define('DOMAIN','sina.com.cn'); define('PROTOCOL','https'); def ...