更弱智的算法学习 day16

第六章 二叉树 part0 4

找树左下角的值

考虑的思想是,按照层序遍历的逻辑,遍历到最后一层的第一个就是树左下角的值。

先考虑使用递归的方法:

创建一个初始化函数,保存需要用到的变量,也即当前最大深度和可更新的结果

然后对二叉树进行遍历,终止条件是root为空;使用深度搜索找到最左下的值,当root的左右子树都不存在,也即root是叶子节点,且此时的深度大于记录的最大深度时,记录新的最大深度和结果;然后继续递归左右子树

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.maxlength = -1
        self.res = -1
    
    def traversal(self,root,leftdepth):
        if not root:
            return 0
        if not root.left and not root.right:
            if leftdepth > self.maxlength:
                self.maxlength = leftdepth
                self.res = root.val
        self.traversal(root.left, leftdepth+1)
        self.traversal(root.right, leftdepth+1)

        
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        self.traversal(root,0)
        return self.res

常规写法可能还是下面这样

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:
        self.maxlength = -1
        self.res = -1
        def traversal(root,leftdepth):
            if not root:
                return 0
            if not root.left and not root.right:
                if leftdepth > self.maxlength:
                    self.maxlength = leftdepth
                    self.res = root.val
            traversal(root.left, leftdepth+1)
            traversal(root.right, leftdepth+1)
            
        traversal(root,0)
        return self.res

这段时间做这部分内容总是不太舒适,感觉不甚理解,仔细研究了一下,找了一些新的思路进行辅助。觉得这个思想没有什么问题,比较框架化,让题目变得好做一些。

二叉树解题的思维模式分两类:

1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。

2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。

无论使用哪种思维模式,你都需要思考:

如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。

如本题,即使用了遍历的方法,想要找到左下角的值,遍历到最后一层即可。traversal函数提供遍历功能性,由主函数最终输出答案。

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:
        self.maxdeep = -1
        self.depth = 0
        self.res = 0

        self.traversal(root)
        return self.res

    def traversal(self, root):
        if not root:
            return 0

        
        if not root.left and not root.right:
            if self.depth > self.maxdeep:
                self.maxdeep = self.depth
                self.res = root.val
                
        self.depth += 1
        self.traversal(root.left)
        self.traversal(root.right)
        self.depth -= 1

路径总和

使用遍历的思想,遍历所有路径获得加和的数组,交给主函数判断。代码如下。

注意回溯的时候像上传要丢弃当前节点的值,也即 -=root.val

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 hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        self.sumpath = 0
        self.res = []
        self.traversal(root,self.res)
        for i in self.res:
            if i == targetSum:
                return True
        return False

        
    def traversal(self, root, res=[]):
        if not root:
            return None
        self.sumpath += root.val
        if not root.left and not root.right:
            res.append(self.sumpath)
        
        self.traversal(root.left, self.res)
        self.traversal(root.right, self.res)
        self.sumpath -= root.val

学习一个分解问题的思路,不断向下检查,到叶子节点时,检查剩余值是否等于该叶子节点值。

python 复制代码
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        
        # 如果是叶子节点,检查当前值是否等于剩余目标值
        if not root.left and not root.right:
            return root.val == targetSum
        
        # 递归检查左右子树
        new_target = targetSum - root.val
        return self.hasPathSum(root.left, new_target) or self.hasPathSum(root.right, new_target)

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

二叉树的构造问题一般都是使用「分解问题」的思路:构造整棵树 = 根节点 + 构造左子树 + 构造右子树

这种方法相对清晰,先就这这个代码捋一遍思路

当后序的数组为空时,说明任务完成,退出递归。

根据示意图,我们知道后序的最后一位也即根节点的数值,首先构造;在中序遍历序列中,根节点左边的是左子树,右边的是右子树;因此从中序序列中找到根节点,划分为中序左和中序右;

相同的,后序遍历中,左子树部分位于序列开头,且长度与左子树的节点数(即 left_size)一致。剩下的部分去掉最后一个值,剩下的都属于右子树。

将二者分别传下去,进行递归。最后输出即可

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)

        left_size = inorder.index(postorder[-1])
        
        inorder_left = inorder[:left_size]
        inorder_right = inorder[left_size + 1:]

        postorder_left = postorder[:left_size]
        postorder_right = postorder[left_size: -1]

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

        return root

另外补充一个从中序和前序构造二叉树

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)

        index_mid = inorder.index(root_val)

        left_inorder = inorder[:index_mid]
        right_inorder = inorder[index_mid+1:]

        left_preorder = preorder[1:index_mid+1]
        right_preorder = preorder[index_mid+1:]

        root.left = self.buildTree(left_preorder,left_inorder)
        root.right = self.buildTree(right_preorder,right_inorder)

        return root
python 复制代码
class Solution:
    # 存储 inorder 中值到索引的映射
    val_to_index = {}

    def buildTree(self, inorder, postorder):
        for i in range(len(inorder)):
            self.val_to_index[inorder[i]] = i
        return self.build(inorder, 0, len(inorder) - 1,
                          postorder, 0, len(postorder) - 1)

    # 定义:中序遍历数组为 inorder[inStart..inEnd],
    # 后序遍历数组为 postorder[postStart..postEnd],
    # build 函数构造这个二叉树并返回该二叉树的根节点
    def build(self, inorder, in_start, in_end,
              postorder, post_start, post_end):

        if in_start > in_end:
            return None
        # root 节点对应的值就是后序遍历数组的最后一个元素
        root_val = postorder[post_end]
        # rootVal 在中序遍历数组中的索引
        index = self.val_to_index[root_val]
        # 左子树的节点个数
        left_size = index - in_start
        root = TreeNode(root_val) 
        # 递归构造左右子树
        root.left = self.build(inorder, in_start, index - 1,
                               postorder, post_start, post_start + left_size - 1)
        
        root.right = self.build(inorder, index + 1, in_end,
                                postorder, post_start + left_size, post_end - 1)
        return root

为了跟内容匹配,今天调整成day16

相关推荐
阿蒙Amon2 小时前
TypeScript学习-第10章:模块与命名空间
学习·ubuntu·typescript
AI绘画哇哒哒2 小时前
【干货收藏】深度解析AI Agent框架:设计原理+主流选型+项目实操,一站式学习指南
人工智能·学习·ai·程序员·大模型·产品经理·转行
那个村的李富贵2 小时前
CANN加速下的AIGC“即时翻译”:AI语音克隆与实时变声实战
人工智能·算法·aigc·cann
power 雀儿2 小时前
Scaled Dot-Product Attention 分数计算 C++
算法
Yvonne爱编码2 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
熬夜有啥好2 小时前
数据结构——哈希表
数据结构·散列表
琹箐2 小时前
最大堆和最小堆 实现思路
java·开发语言·算法
戌中横3 小时前
JavaScript——预解析
前端·javascript·学习
renhongxia13 小时前
如何基于知识图谱进行故障原因、事故原因推理,需要用到哪些算法
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·知识图谱
坚持就完事了3 小时前
数据结构之树(Java实现)
java·算法