更弱智的算法学习 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

相关推荐
hetao17338377 小时前
2026-01-04~06 hetao1733837 的刷题笔记
c++·笔记·算法
橘颂TA7 小时前
【剑斩OFFER】算法的暴力美学——存在重复元素Ⅱ
算法·leetcode·哈希算法·散列表·结构与算法
Boilermaker19927 小时前
[算法基础] DFS
算法
bubiyoushang8888 小时前
MATLAB比较SLM、PTS和Clipping三种算法对OFDM系统PAPR的抑制效果
数据结构·算法·matlab
cg50178 小时前
力扣数据库——组合两个表
sql·算法·leetcode
六边形战士DONK8 小时前
[强化学习杂记] 从数学角度理解贝尔曼最优公式为什么是greedy?
算法
C雨后彩虹8 小时前
计算误码率
java·数据结构·算法·华为·面试
罗湖老棍子9 小时前
【例4-6】香甜的黄油(信息学奥赛一本通- P1345)
算法·图论·dijkstra·floyd·最短路算法·bellman ford
不染尘.9 小时前
进程切换和线程调度
linux·数据结构·windows·缓存