完全二叉树插入器
难度:
标签:
题目描述
完全二叉树 是每一层(除最后一层外)都是完全填充(即,节点数达到最大)的,并且所有的节点都尽可能地集中在左侧。
设计一种算法,将一个新节点插入到一个完整的二叉树中,并在插入后保持其完整。
实现 CBTInserter
类:
CBTInserter(TreeNode root)
使用头节点为root
的给定树初始化该数据结构;CBTInserter.insert(int v)
向树中插入一个值为Node.val == val
的新节点TreeNode
。使树保持完全二叉树的状态,并返回插入节点TreeNode
的父节点的值;CBTInserter.get_root()
将返回树的头节点。
示例 1:
输入 ["CBTInserter", "insert", "insert", "get_root"] [[[1, 2]], [3], [4], []] 输出 [null, 1, 2, [1, 2, 3, 4]] 解释 CBTInserter cBTInserter = new CBTInserter([1, 2]); cBTInserter.insert(3); // 返回 1 cBTInserter.insert(4); // 返回 2 cBTInserter.get_root(); // 返回 [1, 2, 3, 4]
提示:
- 树中节点数量范围为
[1, 1000]
0 <= Node.val <= 5000
root
是完全二叉树0 <= val <= 5000
- 每个测试用例最多调用
insert
和get_root
操作104
次
代码结果
运行时间: 39 ms, 内存: 17.0 MB
/*
题目思路:
1. 使用队列层次遍历树节点并存储在List中。
2. 使用流来筛选出没有两个子节点的节点,作为插入的候选位置。
3. 插入节点时,检查第一个候选节点,如果其左子节点为空则插入到左子节点,否则插入到右子节点。
4. 插入后,更新候选位置列表。
*/
import java.util.*;
import java.util.stream.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
class CBTInserter {
private TreeNode root;
private List<TreeNode> list;
public CBTInserter(TreeNode root) {
this.root = root;
list = new LinkedList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
// 初始化list,保存树的层次遍历节点
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
list.add(node);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
public int insert(int v) {
TreeNode newNode = new TreeNode(v);
for (TreeNode node : list) {
if (node.left == null) {
node.left = newNode;
break;
} else if (node.right == null) {
node.right = newNode;
break;
}
}
list.add(newNode);
return list.stream()
.filter(node -> node.left == newNode || node.right == newNode)
.findFirst()
.map(node -> node.val)
.get();
}
public TreeNode get_root() {
return root;
}
}
解释
方法:
这个题解的思路是使用层序遍历来存储树中的所有节点,这样可以轻松地找到新节点的父节点。对于插入操作,根据完全二叉树的性质,新节点应该被添加为当前最后一个节点的左孩子(如果没有左孩子的话)或者右孩子(如果左孩子已经存在)。我们可以通过当前节点总数来快速定位新节点的父节点。
时间复杂度:
构造函数的时间复杂度为 O(n),插入操作的时间复杂度为 O(1)
空间复杂度:
O(n)
代码细节讲解
🦆
在CBTInserter的初始化过程中,使用层序遍历来获取所有节点,这是否意味着每个节点都被访问一次?是否有更高效的方法来初始化节点列表?
▷🦆
对于insert方法中的计算方式`(len(self.nodes) - 1) // 2`来确定父节点,这种方式是如何保证总是能正确找到父节点的位置?
▷🦆
在insert方法中,如果父节点已有左孩子,则新节点被添加为右孩子。这种插入方式是否总是符合完全二叉树的定义?
▷🦆
CBTInserter类在处理极端情况,如空树(root为None)时的表现如何?这种情况在当前实现中被适当处理了吗?
▷