代码随想录算法训练营第十六天|找树左下角的值 路径总和 从中序与后序遍历序列构造二叉树

写在前边的话

        今天是二叉树训练的第四天,二叉树相关的理论知识在第一天中已经总结了可见下边链接,看今天题目也是比较多的,那就开始吧。

        二叉树理论基础

找树左下角的值

题目链接

        力扣题目链接

题目难度

        中等

看到题目的第一想法

        看到题目的第一想法是想利用层序遍历,遍历每层节点的过程中使用数组保存当前层节点数据,知道最后一层,然后返回数组的第一个数据。

        python

# 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:
        queue = collections.deque([root])
        while queue:
            tmp = []
            n = len(queue)
            for i in range(n):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return tmp[0]
看完代码随想录之后的总结
文章讲解

        代码随想录找树左下角的值文章讲解

视频讲解

        代码随想录找树左下角的值视频讲解

解题思路
递归法

        1. 遍历顺序:前中后都可以,因为没有中的处理逻辑

        2. 递归三部曲:

            入参:当前节点以及深度;不用返回值。

            终止条件:找到叶子节点,更新最大深度,如果当前节点深度大于最大深入则还需要获取节点的值。

            单次递归逻辑:左节点不为空,递归遍历左子树;右节点不为空,递归遍历右子树;注意需要有回溯。

迭代法

        1. 看完代码随想录以后, 没有必要找个列表保存数据,直接保存每层第一个数据就可以了。

代码编写
python
# 递归法
# 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 reversal(self, node, depth):
        if not node.left and not node.right:
            if depth > self.max_depth:
                self.max_depth = depth
                self.res = node.val
                return

        if node.left:
            depth += 1
            self.reversal(node.left, depth)
            depth -= 1  # 回溯
        if node.right:
            depth += 1
            self.reversal(node.right, depth)
            depth -= 1  # 回溯

    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        self.max_depth = float('-inf')
        self.res = None
        self.reversal(root, 0)
        return self.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 findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        queue = collections.deque([root])
        while queue:
            res = 0
            n = len(queue)
            for i in range(n):
                node = queue.popleft()
                if i == 0:
                    res = node.val
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return res
        
java

路径总和

112. 路径总和

题目链接

        力扣题目链接

题目难度

        简单

看到题目的第一想法

        由于前边有写过找二叉树路径的题目用的是递归法,因此看到题目的第一想法就想用递归来解决。

python

# 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 reversal(self, node, targetSum):
        if not node.left and not node.right:
            if sum(self.path) == targetSum:
                self.res = True

        if node.left:
            self.path.append(node.left.val)
            self.reversal(node.left, targetSum)
            self.path.pop()

        if node.right:
            self.path.append(node.right.val)
            self.reversal(node.right, targetSum)
            self.path.pop()

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

        self.path = [root.val]
        self.res = False
        self.reversal(root, targetSum)
        return self.res

注意:

代码不足点:1. 这个代码需要遍历所有的路径,没有做到找到目标路径以后就直接返回,增加了时间复杂度。 2. 使用的是列表保存路径,最后求和,这样会增加时间复杂度和空间复杂度。其实写算法的时候想到了这些问题,但是没找到好的解决办法。

看完代码随想录之后的总结
文章讲解

        代码随想录文章讲解

视频讲解

        代码随想录视频讲解

解题思路
递归法

        1. 遍历顺序:前中后都可以,因为没有中的处理逻辑。

        2. 递归三部曲:

             入参:根节点以及目标值;返回值:布尔值

             终止条件:当前节点的左右节点均为空且目标值减为0,返回true;当前节点的左右节点均为空且目标值不为0,返回false。

            单次递归逻辑:左:遍历左节点不为空则目标值减去左节点的值;然后继续遍历左子树,如果返回true则继续像上一层返回true;目标值加上左节点的值(回溯)。右:遍历右节点不为空则目标值减去右节点的值;然后继续遍历右子树,如果返回true则继续像上一层返回true;目标值加上右节点的值(回溯)

代码编写
python
# 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 reversal(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.reversal(node.left, count):  # 如果找到了一条路径则直接返回了不会进行下边的逻辑了
                return True
            count += node.left.val   # 回溯

        if node.right:
            count -= node.right.val
            if self.reversal(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.reversal(root, targetSum-root.val)

        
java

113. 路径总和||

题目链接

        力扣题目链接

题目难度

        中等

看到题目的第一想法

        看到题目的时候和上边那道题目一样,使用递归法解决。

python

# 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 reversal(self, node, path, targetSum, res):
        if not node.left and not node.right:
            if sum(path) == targetSum:
                res.append(path[:])  # 注意这里需要使用切片或者深拷贝

        if node.left:
            path.append(node.left.val)
            self.reversal(node.left, path, targetSum, res)
            path.pop()
        if node.right:
            path.append(node.right.val)
            self.reversal(node.right, path, targetSum, res)
            path.pop()

        return res
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root:
            return []
        
        path = [root.val]
        res = []
        return self.reversal(root, path, targetSum, res)

注意:添加列表到结果列表的时候,由于入参是列表,因此递归的时候列表中的数据一直在变,因此需要使用切片或深拷贝添加。 

看完代码随想录之后的总结
解题思路
递归法

        解题思路和上边的题目是相似的不同的是需要获取到所有的目标路径并进行保存。

        1. 遍历顺序:前中后都可以,因为没有中的处理逻辑。

        2. 递归三部曲:

            入参:根节点以及目标值;返回值:布尔值

            终止条件:当前节点的左右节点均为空且目标值减为0,添加当前路径到结果列表中然后返回;当前节点的左右节点均为空且目标值不为0,直接返回。

            单次递归逻辑:左:遍历左节点不为空,添加左节点到路径中;然后目标值减去左节点的值;然后继续遍历左子树;目标值加上左节点的值并且路径pop(回溯)。右:遍历右节点不为空,添加右节点到路径中;然后目标值减去右节点的值;然后继续遍历右子树;目标值加上右节点的值并且路径pop(回溯)。

代码编写
python
# 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.path = []
        self.res = []
    def reversal(self, node, count):
        if not node.left and not node.right and count == 0:
            self.res.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.reversal(node.left, count)
            count += node.left.val
            self.path.pop()
        if node.right:
            self.path.append(node.right.val)
            count -= node.right.val
            self.reversal(node.right, count)
            count += node.right.val
            self.path.pop()

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

        self.path.append(root.val)
        self.reversal(root, targetSum-root.val)
        return self.res
        
java

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

题目链接

        力扣题目链接​​​​​​​

题目难度

        中等

看到题目的第一想法

        看到这个题目,没有想到比较好的解决办法。

看完代码随想录之后的总结
文章讲解

        代码随想录文章讲解

视频讲解

       代码随想录视频讲解

解题思路

        1. 递归法

        2. 解题步骤

            1)树为空了,则返回空(递归终止条件)

            2)后序遍历的最后一个元素就是当前的中间节点

            3)在中序遍历中查找切割点

            4)切割中序遍历的数组,切割为左中序和右中序

            5)切割后序遍历的数组

            6)递归

代码编写
python
# 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 not postorder:
            return None

        root_val = postorder[-1]
        root = TreeNode(root_val)

        root_index = inorder.index(root_val)

        inorder_left = inorder[:root_index]
        inorder_right = inorder[root_index + 1:]

        postorder_left = postorder[:len(inorder_left)]
        postorder_right = postorder[len(inorder_left):len(postorder)-1]

        root.left = self.buildTree(inorder_left, postorder_left)
        root.right = self.buildTree(inorder_right, postorder_right)

        return root

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

        解题思路同上。

        python

# 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 not preorder:
            return None

        root_val = preorder[0]
        root = TreeNode(root_val)

        root_index = inorder.index(root_val)
        print(f"root_index: {root_index}")
        
        inorder_left = inorder[:root_index]
        inorder_right = inorder[root_index+1:]

        preorder_left = preorder[1: len(inorder_left)+1]
        preorder_right = preorder[len(inorder_left)+1:]

        root.left = self.buildTree(preorder_left, inorder_left)
        root.right = self.buildTree(preorder_right, inorder_right)

        return root

今日总结

        今天也是用递归解题的一天,感觉更加熟悉了,只要有思路然后按照递归三步曲(入参返回值、终止条件、单次递归逻辑)按部就班的来思考就问题不会特别大了。然后是今天构造二叉树的题目,由于没接触过这类题目,没什么思路,训练完思路也是比较清晰了(前序和中序、后序和中序均可以唯一确定二叉树,前序和后序不能,因为必须要有中序才能确定左右部分才能进行分割)。

  • 31
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值