919. Complete Binary Tree Inserter**
https://leetcode.com/problems/complete-binary-tree-inserter/
题目描述
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 aTreeNode into the tree with valuenode.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:
- The initial given tree is complete and contains between
1 and1000 nodes. -
CBTInserter.insert is called at most10000 times per test case. - Every value of a given or inserted node is between
0 and5000.
C++ 实现 1
为了方便在完全二叉树中插入新节点并保证新的二叉树仍然是完全二叉树, 需要确定当前可以接受新节点的父节点. 比如:
0
/ \
1 2
/ \
3 4
要是插入新节点 5 的话, 我们需要找到 2 这个节点, 并将 5 作为 2 的左孩子. 为了达到这个目的, 使用层序遍历记录下每一个节点, 并用 k 指向我们期望的父节点. 观察完全二叉树可以了解其特点是, 如果某节点的索引为 i, 那么其左孩子为 2 * i + 1, 右孩子为 2 * i + 2. 同样的, 如果知道了某个孩子的索引, 也可以求出父节点的索引, 但是, 注意这里一个较好的性质是, 直接用孩子的索引除以 2, 可以得到下一个可以插入新节点的父节点的索引, 原因是, 如果这个完全二叉树的最后一个节点是某个父节点 A 的左孩子, A 的索引可以用 (2 * i + 1) / 2 = i 得到, 之后新插入的节点继续插入到 A 的右指针中. 而如果这个完全二叉树最后一个节点是某个父节点 A 的右孩子, 用右孩子的索引除以 2 为 (2 * i + 2) / 2 = i + 1, 这个结果是 i + 1 而不是 i, 刚好是下一个可以插入新节点的父节点的索引. 毕竟, 此时节点 A 的左右孩子都有了, 不能再插入节点了.
确定好 k 之后, 之后来了新节点, 使用 2 * k + 1 >= record.size() 来判断是插入到父节点的左指针中还是右指针中. 注意如果插入到左指针中, 那么 k 不用移动了. 而如果插入到右指针中, 则 k 要移动指向下一个节点, 因此 k 指向的节点此时拥有了左右两个孩子.
class CBTInserter {
private:
vector<TreeNode*> record;
int k;
public:
CBTInserter(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
auto size = q.size();
for (int i = 0; i < size; ++ i) {
auto r = q.front();
q.pop();
record.push_back(r);
if (r->left) q.push(r->left);
if (r->right) q.push(r->right);
}
}
k = (record.size() - 1) / 2;
}
int insert(int v) {
auto node = new TreeNode(v);
auto parent = record[k];
if (2 * k + 1 >= record.size()) {
parent->left = node;
} else {
parent->right = node;
++ k;
}
record.push_back(node);
return parent->val;
}
TreeNode* get_root() {
return record[0];
}
};
/**
* Your CBTInserter object will be instantiated and called as such:
* CBTInserter* obj = new CBTInserter(root);
* int param_1 = obj->insert(v);
* TreeNode* param_2 = obj->get_root();
*/
