装饰树

标签: 深度优先搜索 广度优先搜索 二叉树

难度: Medium

力扣嘉年华上的 DIY 手工展位准备了一棵缩小版的 **二叉** 装饰树 `root` 和灯饰,你需要将灯饰逐一插入装饰树中,要求如下: - 完成装饰的二叉树根结点与 `root` 的根结点值相同 - 若一个节点拥有父节点,则在该节点和他的父节点之间插入一个灯饰(即插入一个值为 `-1` 的节点)。具体地: - 在一个 父节点 x 与其左子节点 y 之间添加 -1 节点, 节点 -1、节点 y 为各自父节点的左子节点, - 在一个 父节点 x 与其右子节点 y 之间添加 -1 节点, 节点 -1、节点 y 为各自父节点的右子节点, 现给定二叉树的根节点 `root` ,请返回完成装饰后的树的根节点。 **示例 1:** >输入: >`root = [7,5,6]` > >输出:`[7,-1,-1,5,null,null,6]` > >解释:如下图所示, >![image.png](https://pic.leetcode-cn.com/1663575757-yRLGaq-image.png){:width=400px} **示例 2:** >输入: >`root = [3,1,7,3,8,null,4]` > >输出:`[3,-1,-1,1,null,null,7,-1,-1,null,-1,3,null,null,8,null,4]` > >解释:如下图所示 ![image.png](https://pic.leetcode-cn.com/1663577920-sjrAYH-image.png){:width=500px} **提示:** >`0 <= root.Val <= 1000` >`root` 节点数量范围为 `[1, 10^5]`

Submission

运行时间: 204 ms

内存: 38.5 MB

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def expandBinaryTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if root==None:return None
        if root.left==None and root.right==None:return root
        if root.left!=None:
            node=TreeNode(-1)
            node.left=root.left
            root.left=node
            node.right=None
            self.expandBinaryTree(node.left)
        if root.right!=None:
            node=TreeNode(-1)
            node.right=root.right
            root.right=node
            node.left=None
            self.expandBinaryTree(node.right)
        return root

Explain

此题的核心思路是在原二叉树的每个节点与其子节点之间插入一个值为-1的新节点。递归方法是用来遍历每个节点,并在遍历过程中插入新节点。如果当前节点有左子节点,则在当前节点的左子节点前插入一个值为-1的新节点,并将原左子节点变为新插入节点的左子节点。同样的处理适用于右子节点。递归继续对新插入的(值为-1的)节点的左或右子节点(视原始子节点位置而定)调用同样的过程,直到所有的子节点都被处理完毕。

时间复杂度: O(n)

空间复杂度: O(n)

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def expandBinaryTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if root==None: return None # 若根为空,直接返回None
        # 叶节点直接返回,因为无需在其与子节点之间插入新节点
        if root.left==None and root.right==None: return root
        if root.left!=None: # 处理左子树
            node=TreeNode(-1) # 创建新节点
            node.left=root.left # 将新节点的左子节点设为原左子节点
            root.left=node # 将原根节点的左子节点更新为新节点
            node.right=None # 新节点的右子节点为空
            self.expandBinaryTree(node.left) # 递归处理新的左子节点
        if root.right!=None: # 处理右子树
            node=TreeNode(-1) # 创建新节点
            node.right=root.right # 将新节点的右子节点设为原右子节点
            root.right=node # 将原根节点的右子节点更新为新节点
            node.left=None # 新节点的左子节点为空
            self.expandBinaryTree(node.right) # 递归处理新的右子节点
        return root

Explore

在本题的逻辑中,只有在父节点与子节点之间才需要插入值为-1的新节点。对于叶子节点,由于它们没有子节点,因此不存在需要在其与子节点之间插入新节点的情况。直接返回叶子节点,是为了避免在没有子节点的节点后面错误地添加额外的节点,保持树的结构正确且符合题目要求。

在插入-1的新节点后,新节点实际上取代了原节点作为子节点的位置,而原来的子节点现在成为了新插入的-1节点的子节点。递归调用`expandBinaryTree`函数处理新插入节点的子节点是为了保证每个原有的父子关系中间都正确地插入了-1节点。如果递归调用原始的子节点而非新插入的节点,那么新插入的-1节点的子节点将不会被递归处理,从而导致新插入的节点没有正确地连接到树的其余部分。

如果根节点为空,则表明二叉树不存在,因此返回None是对此情况的合理处理。这种处理方式通常适用于许多二叉树相关的问题,因为它处理了树为空的边界情况。特别是在涉及到递归操作的二叉树问题中,检查根节点是否为空是一个常见的安全措施,避免在空树上执行进一步的操作。因此,这不仅是特定于本题的要求,而是一种普遍适用的处理方式。