代码随想录|Day16|二叉树05|513.找树左下角的值、112.路径总和、113.路径总和II、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

本题要求找出该二叉树的 最底层 最左边 节点的值。

实际上是寻找深度最大的叶子结点中最左边的一个。

注意,满足条件的节点并不一定是左孩子。如下图所示,节点5虽然是节点3的右子孩子,但依然符合 最底层 最左边 这一条件。

首先定义一个全局变量,maxDepth,用于记录遍历到某叶子节点时,当前的最大深度,当我们到达新的叶子节点时,检查这个深度是否大于 maxDepth,如果大于,则更新结果。

需要注意的是,我们必须采用先左后右的顺序,否则,左右叶子节点否存在的情况下,会优先保存右叶子节点。

如下图所示,节点4是需要收集的最终结果。若我们采取先右后左的顺序。

当到达节点3时,若先遍历右子树到达节点5,此时由于5是叶子结点且深度更大,我们会收集节点5,并更新最大深度为3。

回到节点3,接着遍历左子树到达节点4,此时虽然4是叶子结点,但是深度并不大于3,因此不会记录节点4。

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        self.max_depth = float('-inf')
        self.result = 0
        self.traversal(root, 0)
        return self.result
    
    def traversal(self, node, depth):
        # 如果为叶子节点,则记录最大深度并收集值
        if not node.left and not node.right:
            if depth > self.max_depth:
                self.max_depth = depth
                self.result = node.val
            return
        # 如果不是叶子结点,继续向下递归
        # 若调换左右遍历顺序,某些用例无法通过
        if node.left:
            depth += 1
            self.traversal(node.left, depth)
            depth -= 1
        if node.right:
            depth += 1
            self.traversal(node.right, depth)
            depth -= 1

本题使用层序遍历会比较好理解。

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        # 层序遍历
        if not root:
            return None
        queue = deque([root])
        left_most_value = 0

        while queue:
            level_size = len(queue)
            # 维护每一层最左边节点的元素值
            left_most_value = queue[0].val

            for i in range(level_size):
                node = queue.popleft()
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        
        return left_most_value

112.路径总和

只需要遍历到一条符合条件的路径,即可终止搜索。因此递归函数需要一个返回值。

在 113. 路径综合II中,则需要找出所有的路径,因此不需要返回值。

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        return self.traversal(root, targetSum - root.val)
    
    def traversal(self, node, count):

        if not node.left and not node.right and count == 0:
            return True
        if not node.left and not node.right and count != 0:
            return False
        
        if node.left:
            count -= node.left.val
            if self.traversal(node.left, count):
                return True
            count += node.left.val
        
        if node.right:
            count -= node.right.val
            if self.traversal(node.right, count):
                return True
            count += node.right.val
        
        return False

113.路径总和II

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        self.result = []
        self.path = []
        if not root:
            return self.result
        self.path.append(root.val)
        self.traversal(root, targetSum - root.val)
        return self.result

    def traversal(self, node, count):

        if not node.left and not node.right and count == 0:
            self.result.append(self.path[:])
            return
        if not node.left and not node.right and count != 0:
            return
        
        if node.left:
            self.path.append(node.left.val)
            count -= node.left.val

            self.traversal(node.left, count)

            count += node.left.val
            self.path.pop()
        
        if node.right:
            self.path.append(node.right.val)
            count -= node.right.val

            self.traversal(node.right, count)

            count += node.right.val
            self.path.pop()

106.从中序与后序遍历序列构造二叉树

中序和后序都以特定的方式提供了树的信息:

  • 中序遍历:每个节点的左子树和右子树分别位于该节点的左右侧
  • 后序遍历:每个子树的最后一个元素是该子树的根节点

从根节点开始构造二叉树,首先定位到后序遍历的最后一个元素,其为此二叉树的根节点。在中序遍历中,此元素左边的元素构成左子树,右边的元素构成右子树。

class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:

        if not inorder or not postorder:
            return None
        # 后序遍历的最后一个元素是根节点
        root_val = postorder.pop()
        # 创建一个根节点,下面对其左右指针赋值
        root = TreeNode(root_val)
        # 根节点在中序遍历中的位置
        index = inorder.index(root_val)

        # 接下来是对中序和后序的切片
        
        # 首先来看中序:左中右
        # 根节点在inorder中的索引为index,意味index左边的元素全部为左子树,inorder[:index]
        # index右边的元素全部为右子树,inorder[index+1:]

        # 其次来看后序:左右中
        # 根节点在inorder中的索引为index,意味着左子树元素有index个,postorder[:index]
        # 除开前index个和最后一个元素(已经pop)外,都为右子树元素,postorder[index:]
        root.left = self.buildTree(inorder[:index], postorder[:index])
        root.right = self.buildTree(inorder[index+1:], postorder[index:])

        return root

105.从前序与中序遍历序列构造二叉树

  • 前序遍历:每个子树的第一个元素是该子树的根节点
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        
        if not preorder and not inorder:
            return None
        
        root_val = preorder[0]
        root = TreeNode(root_val)

        index = inorder.index(root_val)
        # 接下来是对中序和前序的切片
        
        # 首先来看中序:左中右
        # 根节点在inorder中的索引为index,意味index左边的元素全部为左子树,inorder[:index]
        # index右边的元素全部为右子树,inorder[index+1:]

        # 其次来看前序:中左右
        # 根节点在inorder中的索引为index,意味着左子树元素有index个,
        # 由于preorder中的根节点并没被移除,从第二个开始的index个元素为左子树元素,preorder[1:index+1]
        # 剩余都为右子树元素,preorder[index+1:]
        root.left = self.buildTree(preorder[1 : index+1], inorder[ :index])
        root.right = self.buildTree(preorder[index+1 :], inorder[index+1 :])

        return root
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值