标题:在二叉树中增加一行
出处:623. 在二叉树中增加一行
5 级
给定一个二叉树的根结点 root \texttt{root} root 和两个整数 val \texttt{val} val 和 depth \texttt{depth} depth,在给定的深度 depth \texttt{depth} depth 处添加一行值为 val \texttt{val} val 的结点。
注意,根结点 root \texttt{root} root 位于深度 1 \texttt{1} 1。
添加规则如下:
示例 1:
输入: root = [4,2,6,3,1,5], val = 1, depth = 2 \texttt{root = [4,2,6,3,1,5], val = 1, depth = 2} root = [4,2,6,3,1,5], val = 1, depth = 2
输出: [4,1,1,2,null,null,6,3,1,5] \texttt{[4,1,1,2,null,null,6,3,1,5]} [4,1,1,2,null,null,6,3,1,5]
示例 2:
输入: root = [4,2,null,3,1], val = 1, depth = 3 \texttt{root = [4,2,null,3,1], val = 1, depth = 3} root = [4,2,null,3,1], val = 1, depth = 3
输出: [4,2,null,1,1,3,null,null,1] \texttt{[4,2,null,1,1,3,null,null,1]} [4,2,null,1,1,3,null,null,1]
如果 depth = 1 \textit{depth} = 1 depth=1,则创建值为 val \textit{val} val 的新的根结点,将原二叉树作为新的根结点的左子树,返回新的根结点即可。
当 depth > 1 \textit{depth} > 1 depth>1 时,添加一行结点不会改变根结点,只要定位到添加结点的层,完成添加操作之后返回根结点即可。
根据添加规则,结点应该添加在深度 depth \textit{depth} depth 的行。令 level = depth − 1 \textit{level} = \textit{depth} - 1 level=depth−1,需要定位到第 level \textit{level} level 层的全部结点,对于该层的每个结点添加两个子结点,并将原左子树和原右子树分别作为新左子结点的左子树和新右子结点的右子树。
定位到特定层添加结点可以使用深度优先搜索实现,深度优先搜索的过程中需要记录位于当前结点时应该添加在当前子树的哪一层,初始时位于根结点,层数 level = depth − 1 \textit{level} = \textit{depth} - 1 level=depth−1。搜索过程中,如果 level = 1 \textit{level} = 1 level=1,则对于当前结点添加两个子结点,并将原左子树和原右子树分别作为新左子结点的左子树和新右子结点的右子树。如果 level > 1 \textit{level} > 1 level>1,则对于每个非空结点,将层数减 1 1 1 之后继续深度优先搜索。
上述过程是一个递归的过程,递归的终止条件是 level = 1 \textit{level} = 1 level=1,当 level > 1 \textit{level} > 1 level>1 时调用递归。
class Solution {
public TreeNode addOneRow(TreeNode root, int val, int depth) {
if (depth == 1) {
return new TreeNode(val, root, null);
}
insert(root, val, depth - 1);
return root;
}
public void insert(TreeNode node, int val, int level) {
TreeNode left = node.left, right = node.right;
if (level == 1) {
node.left = new TreeNode(val, left, null);
node.right = new TreeNode(val, null, right);
} else {
if (left != null) {
insert(left, val, level - 1);
}
if (right != null) {
insert(right, val, level - 1);
}
}
}
}
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。每个结点最多访问一次。
空间复杂度: O ( depth ) O(\textit{depth}) O(depth)。空间复杂度主要是递归调用的栈空间,栈空间的深度是 O ( depth ) O(\textit{depth}) O(depth)。
也可以使用广度优先搜索实现,具体做法是使用层序遍历定位到添加结点的层,然后对于该层的每个结点添加两个子结点,并将原左子树和原右子树分别作为新左子结点的左子树和新右子结点的右子树。
从根结点开始依次遍历每一层的结点,在层序遍历的过程中需要记录遍历的层数,并区分不同结点所在的层,确保每一轮访问的结点为同一层的全部结点。遍历每一层结点之前首先得到当前层的结点数,即可确保每一轮访问的结点为同一层的全部结点。遍历完一层结点之后需要将层数加 1 1 1。
使用队列存储待访问的结点,初始时队列中只有根结点,层数为 1 1 1。当层数等于 depth − 1 \textit{depth} - 1 depth−1 时,队列中的结点即为需要添加子结点的全部结点,对于队列中的每个结点添加两个子结点,并将原左子树和原右子树分别作为新左子结点的左子树和新右子结点的右子树。
class Solution {
public TreeNode addOneRow(TreeNode root, int val, int depth) {
if (depth == 1) {
return new TreeNode(val, root, null);
}
int level = 1;
Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
queue.offer(root);
while (!queue.isEmpty() && level < depth - 1) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
TreeNode left = node.left, right = node.right;
if (left != null) {
queue.offer(left);
}
if (right != null) {
queue.offer(right);
}
}
level++;
}
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
TreeNode left = node.left, right = node.right;
node.left = new TreeNode(val, left, null);
node.right = new TreeNode(val, null, right);
}
return root;
}
}
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。每个结点最多被访问一次。
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是队列空间,队列内元素个数不超过 n n n。