算法刷题打卡016 | 二叉树相关题目5道

LeetCode 513 找树左下角的值

题目链接:513. 找树左下角的值 - 力扣(Leetcode)

确实乍一看题目很容易想到用二叉树的层序遍历就能解决问题:

# 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 findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        # 层序遍历
        q = collections.deque()
        q.append(root)
        res = 0
        while q:
            n = len(q)
            for i in range(n):
                cur = q.popleft()
                if i == 0:
                    res = cur.val
                if cur.left:
                    q.append(cur.left)
                if cur.right:
                    q.append(cur.right)
        return res

而递归思路的难点在于如何找到最后一行。这时需要借助树的深度,深度最大的叶节点位于最后一层,按从左到右的顺序遍历就可以优先找到该行的第一个叶节点。

# 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 __init__(self):
        self.maxdepth = -1
        self.result = 0

    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        # 递归
        def dfs(node, depth):
            if not node.left and not node.right:
                # 只要深度大于原最大深度才会更新和获得节点值
                # (等于时也不会进入if语句,因此能保证result获得的都是每一层的最左边叶节点值)
                if depth > self.maxdepth:
                    self.maxdepth = depth
                    self.result = node.val
                return
            if node.left:
                dfs(node.left, depth + 1)
            if node.right:
                dfs(node.right, depth + 1)   
            return
        dfs(root, 0)
        return self.result

实现时在Python类中实现了__init__函数,初始化全局变量,若递归时深度从0开始,最大深度的初始值就不能设为0,否则root为叶节点时就会出错。

LeetCode 112 路径总和

题目链接:112. 路径总和 - 力扣(Leetcode)

这题路径总和只需要找到其中一条满足条件的路径即可,在深度优先遍历递归过程中传入当前节点和剩余总和值curSum(targetSum-前面已遍历节点的值之和),遇到叶子节点时就能判断curSum和当前节点值是否相等。和讲解实现的差异是这里dfs初始时传入的是targetSum,默认传入dfs的node还没有遍历到,而讲解中初始时传入的是targetSum-root.val,所以会在叶节点处判断curSum是否等于0。

# 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 hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        def dfs(node, curSum):
            # 节点值可以为负数,不能这样剪枝
            # if curSum < 0:
            #     return False
            # 遇到叶节点
            if not node.left and not node.right:
                return True if curSum == node.val else False
            res = False
            if node.left:
                left = dfs(node.left, curSum - node.val)
                res = res or left
            if node.right:
                right = dfs(node.right, curSum - node.val)
                res = res or right
            return res
        
        result = dfs(root, targetSum)
        return result

实现时要注意细节,开始时下意识加了和为负数的剪枝,但题目的节点值可以为负数,和也可以是负数,这种情况下就不能做剪枝。 

LeetCode 113 路径总和II

题目链接: 113. 路径总和 II - 力扣(Leetcode)

本题和路径总和思路相同,只需要把叶节点处返回bool值的逻辑修改为收集结果,并且在左右子树的递归逻辑前后加入路径的添加和回溯:

# 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 pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root:
            return []
        result, path = [], []
        def dfs(node, curSum):
            # 遇到叶节点
            if not node.left and not node.right:
                if curSum == node.val:
                    result.append(path[:] + [node.val])
            if node.left:
                path.append(node.val)
                dfs(node.left, curSum - node.val)
                path.pop()
            if node.right:
                path.append(node.val)
                dfs(node.right, curSum - node.val)
                path.pop()
        
        dfs(root, targetSum)
        return result

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

题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(Leetcode)

# 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 buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        
        def build(pre_left, pre_right, in_left, in_right):
            # 用下标标记数组的区间,左闭右开
            if pre_right <= pre_left:
                return None
            root = TreeNode(val=preorder[pre_left])
            in_idx = inorder.index(preorder[pre_left])  # 根节点在inorder中的下标
            len_left = in_idx - in_left  # 左子树的节点数
            root.left = build(pre_left+1, pre_left+1+len_left, in_left, in_idx)
            root.right = build(pre_left+1+len_left, pre_right, in_idx+1, in_right)
            return root
        
        n = len(preorder)  # 节点总数
        root = build(0, n, 0, n)
        return root

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

题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(Leetcode)

# 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 buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
                
        def build(post_left, post_right, in_left, in_right):
            # 用下标标记数组的区间,左闭右开
            if post_right <= post_left:
                return None
            root = TreeNode(val=postorder[post_right-1])
            in_idx = inorder.index(postorder[post_right-1])  # 根节点在inorder中的下标
            len_left = in_idx - in_left  # 左子树的节点数
            root.left = build(post_left, post_left+len_left, in_left, in_idx)
            root.right = build(post_left+len_left, post_right-1, in_idx+1, in_right)
            return root
        
        n = len(postorder)  # 节点总数
        root = build(0, n, 0, n)
        return root

106和105的构造二叉树不难,只要理解如何根据前序或后序数组,递归划分两个遍历序列即可。实现时会稍微繁琐一些,需要维护两个数组的切割,还要注意区间的开闭性质。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值