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

63 阅读4分钟

513. 找树左下角的值 - 力扣(LeetCode)

1. 第一想法

层序遍历, 最后一层的第一个元素就是我们要找的元素。

# 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:
        node_queue = deque()
        node_queue.append(root)
        res_list = []
        while node_queue:
            size = len(node_queue)
            for i in range(size):
                node = node_queue.popleft()
                if i == 0:
                    res_list.append(node.val)
                if node.left:
                    node_queue.append(node.left)
                if node.right:
                    node_queue.append(node.right)
        return res_list[-1]

2. 看过文档后

代码随想录 (programmercarl.com) 思路差不多。 但是文档不使用res_list记录每一层的第一个,而是直接用一个变量,不断用list的第一个元素赋值。

3. 学习时长

10分钟。

112. 路径总和 - 力扣(LeetCode)

1. 第一想法

前序遍历。 但是前序遍历过程中,如果我们只使用一个变量统计一条路径的val的总和,那我们在当前叶子节点是其parent的右孩子时,如果我们要回退,我们会发现最多回退到它的parent,而因为parent早已经在之前给左右孩子压入栈时从栈中pop出来,所以这里根本没有办法再往回退。这就是我们实现迭代法前序遍历的唯一障碍。

2. 看完文档的收获。

代码随想录 (programmercarl.com) 此时,我们应该不仅仅只用stack记录node,还要记录从root到当前节点node的路径中val总和。

stack.append((node, sum(root-->node)))

所以具体实现如下:

# 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 root is None:
            return False
        else:
            node_stack = list()
            node_stack.append((root, root.val))
            while node_stack:
                node, node_sum = node_stack.pop()
                if (not node.left) and (not node.right):
                    if node_sum == targetSum:
                        return True
                if node.right:
                    node_stack.append((node.right, node_sum + node.right.val))
                if node.left:
                    node_stack.append((node.left, node_sum + node.left.val))
            return False
                

3. 学习时长

1小时。

113. 路径总和 II - 力扣(LeetCode)

1. 第一想法

同样是和上面一样的前序遍历,但是需要记录路径。 如果需要记录路径,我们就需要找到记录的时机。

只有当遇到叶子节点的时候,才能凑齐一条路径。 但是如果直到叶子节点才记录一条路径,实际上是没办法回溯的。 就像上一道题的困境一样,于是我的笨办法是,每个节点都要记录自己到root的路径列表,虽然存储占的大,但是能保证每一个叶子节点统计到真实的到root的路径。

2. 看过文档后的收获

代码随想录 (programmercarl.com)

至于113. 路径总和ii 的迭代法我并没有写,用迭代方式记录所有路径比较麻烦,也没有必要,如果大家感兴趣的话,可以再深入研究研究。

发现他并没有使用迭代法,而是直接递归,这个很方便,我也可以用递归来实现,就不知难而上了。

  • 终止条件:如果节点是叶子,那就判断是否满足sumTarget,如果是则将当前路径加入到route_list,然后返回。
  • 传入参数:当前root和一个临时路径,他从root出发,到叶子节点。以及从root到当前节点的value总和。
  • 本层逻辑:
    • 将value + root.val, list.append(root.val)
    • 传给左侧子树递归,
    • 传给右侧子树递归.
# 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.route_list = []

    def dfs(self, root, sum_val, targetSum, route: list):
        if (not root.left) and (not root.right):
            if sum_val + root.val == targetSum:
                self.route_list.append(route + [root.val])
        else:
            if root.left:
                self.dfs(root.left, sum_val + root.val, targetSum, route + [root.val])
            if root.right:
                self.dfs(root.right, sum_val + root.val, targetSum, route + [root.val])

    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if root is None:
            return []
        else:
            self.dfs(root, 0, targetSum, [])
            return self.route_list

3. 学习时长

40分钟。

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

1. 直接看文档

用后序遍历的后侧节点来分割中序遍历的序列,从而得到左右子树的后序遍历和中序遍历的序列。

所以我们使用分治递归去做。

# 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]:
        if postorder is None or len(postorder) == 0:
            return None
        root_val = postorder[-1]
        root_inorder_idx = -1
        for idx in range(len(inorder)):
            if inorder[idx] == root_val:
                root_inorder_idx = idx
                break
        left_child = self.buildTree(inorder[:root_inorder_idx], postorder[:root_inorder_idx])
        right_child = self.buildTree(inorder[root_inorder_idx + 1 :], postorder[root_inorder_idx:-1])
        return TreeNode(val=root_val, left=left_child, right=right_child)

3. 学习时长

30分钟

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

1. 第一想法

和上述思路一样。

# 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]:
        if (preorder is None) or (len(preorder) == 0):
            return None
        else:
            root_val = preorder[0]
            mid_idx = -1
            for idx in range(len(inorder)):
                if inorder[idx] == root_val:
                    mid_idx = idx
                    break
            left_child = self.buildTree(preorder[1:mid_idx + 1], inorder[:mid_idx])
            right_child = self.buildTree(preorder[mid_idx + 1:], inorder[mid_idx + 1:])
            return TreeNode(val=root_val, left=left_child, right=right_child)

2. 学习时长

5分钟。