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

一、513.找树左下角的值

题目链接:513. 找树左下角的值 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——513.找树左下角的值
视频讲解:怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值_哔哩哔哩_bilibili

1. 层序遍历

"""
层序遍历,返回最后一组数组的第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:

        # 定义一个队列
        que = collections.deque()
        res = []
 
        # 如果根节点不为空则加入队列
        if root is not None:
            que.append(root)
 
        # 遍历终止条件为队列中没有元素了
        while que:
            # 记录当前层节点数
            size = len(que)
 
            # 定义一个数组放当前层元素
            vator = []
 
            for i in range(size):
                # 从队列中弹出当前节点
                cur = que.popleft()
                # 将当前节点值放到当前层的结果中
                vator.append(cur.val)
 
                # 将节点左右子节点加入队列
                if cur.left:
                    que.append(cur.left)
                if cur.right:
                    que.append(cur.right)
            
            # 将当前层元素加入结果
            res.append(vator)
 
        return res[-1][0]

2. 递归

思路:找深度最大的叶子节点

"""
递归,找左右子节点,不用考虑中,因此哪种遍历顺序都可以
"""
# 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:
    # 1. 确定递归函数的参数和返回值
    def traversal(self, node, depth):
        # 2. 确定终止条件,左右子节点都为空
        if not node.left and not node.right:
            # 遇到叶子节点深度大于我当前最大深度,更新最大深度,并记录当前节点数值
            if depth > self.max_depth:
                self.max_depth = depth
                self.result = node.val
            
        # 3. 单层递归
        # 左
        if node.left:
            depth += 1
            self.traversal(node.left, depth)    # 回溯
            depth -= 1

        # 右
        if node.right:
            depth += 1
            self.traversal(node.right, depth)
            depth -= 1


    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        self.max_depth = float('-inf')
        self.result = None
        self.traversal(root, 0)

        return self.result

二、路经总和

112. 路径总和

题目链接:112. 路径总和 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——112. 路径总和
视频讲解:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和_哔哩哔哩_bilibili

"""
错误代码!
递归,没有中的逻辑,那种遍历顺序都可以
"""
# 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:
    # 1. 确定递归函数的参数和返回值,count为目标值
    def traversal(self, node, count):
        # 2. 确定终止条件
        # 为叶子节点且count--后为0
        if not node.left and not node.right and count == 0:
            return True
        # 为叶子节点但count--后不为0
        if not node.left and not node.right and count != 0:
            return False

        # 3. 确定单层递归的逻辑
        # 判断左节点不为空
        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

    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        
        # 返回值出错,目标值要减去根节点值
        return self.traversal(root, targetSum)
"""
正确代码
递归,没有中的逻辑,那种遍历顺序都可以
"""
# 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:
    # 1. 确定递归函数的参数和返回值,count为目标值
    def traversal(self, node, count):
        # 2. 确定终止条件
        # 为叶子节点且count--后为0
        if not node.left and not node.right and count == 0:
            return True
        # 为叶子节点但count--后不为0
        if not node.left and not node.right and count != 0:
            return False

        # 3. 确定单层递归的逻辑
        # 判断左节点不为空
        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

    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False

        return self.traversal(root, targetSum - root.val)

113. 路径总和ii

题目链接:113. 路径总和 II - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——113. 路径总和ii

# 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.result = []
        self.path = []

    # 1. 确定递归函数的参数和返回值
    def traversal(self, node, count):
        # 2. 确定终止条件
        # 为叶子节点且总和为目标值,将其加入path种
        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

        # 3. 确定单层递归逻辑
        # 左
        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()                     # 回溯
        
        return


    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root:
            return self.result

        # 根节点放入路径
        self.path.append(root.val)
        self.traversal(root, targetSum - root.val)

        return self.result

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

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

题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——106.从中序与后序遍历序列构造二叉树
视频讲解:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树_哔哩哔哩_bilibili

思路:
① 后序数组为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 buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        # 第1步,后序数组为0,则空节点
        if len(postorder) == 0:
            return None

        # 第2步,后序数组最后一个元素为根节点
        root_val = postorder[-1]
        root = TreeNode(root_val)
        if len(postorder) == 1:
            return root

        # 第3步,根节点作为中序数组的切割点,分成左右区间
        index = 0
        for index in range(len(inorder)):
            if inorder[index] == root_val:
                break
        
        # 第4步,切割中序数组
        inorder_left = inorder[:index]
        inorder_right = inorder[index + 1:]

        # 第5步,切割后序数组,根据中序数组左右区间长度
        postorder_left = postorder[:len(inorder_left)]
        postorder_right = postorder[len(inorder_left):len(postorder) - 1]

        # 第6步,递归处理左右区间
        root.left = self.buildTree(inorder_left, postorder_left)
        root.right = self.buildTree(inorder_right, postorder_right)

        return root

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

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

思路:
① 前序数组为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 buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        # 第1步,前序数组为0,则空节点
        if len(preorder) == 0:
            return None

        # 第2步,前序数组第一个元素为根节点
        root_val = preorder[0]
        root = TreeNode(root_val)

        # 第3步,根节点作为中序数组的切割点,分成左右区间
        index = 0
        for index in range(len(preorder)):
            if inorder[index] == root_val:
                break
        
        # 第4步,切割中序数组
        inorder_left = inorder[:index]
        inorder_right = inorder[index + 1:]

        # 第5步,根据中序数组左右区间长度,切割前序数组
        preorder_left = preorder[1:1 + len(inorder_left)]
        preorder_right = preorder[1 + len(inorder_left):]

        # 第6步,递归处理左右区间
        root.left = self.buildTree(preorder_left, inorder_left)
        root.right = self.buildTree(preorder_right, inorder_right)

        return root

你可能感兴趣的:(代码随想录算法训练营,数据结构)