Day 18 | 二叉树

38 阅读3分钟

513. 找树左下角的值

  • 迭代法 用层序遍历(可以调整为只添加第一个节点)
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
    if not root:
        return

    que = [root]
    res = []

    while que:
        n = len(que)
        tmp = []
        while n:
            node = que.pop(0)
            if node.left:
                que.append(node.left)
            if node.right:
                que.append(node.right)
            tmp.append(node.val)
            n -= 1
        res.append(tmp)
    return res[-1][0]

112.路径总和

思路:

与遍历顺序无关

利用和targetSum的差值传参

递归三部:

终止条件:count==0; none值

if not node.left and not node.right:
    return count == 0

遍历顺序:

其实没有对中节点的处理过程,所以相当于前中后遍历都可以

递归过程中,如果遇到返回值为true的,一级级返回上去

分别进行左右遍历

回溯:把节点值加回count 即回退

def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
    if not root:
        return False
    
    def recursion(root, targetRes):
        if not root:
            return False
        if not root.left and not root.right:
            return targetRes == 0 
        
        if root.left and recursion(root.left, targetRes-root.left.val):
            return True

        if root.right and recursion(root.right, targetRes-root.right.val):
            return True
        return False
    
    # initial val
    return recursion(root, targetSum-root.val)

113. 路径总和 II

因为要遍历整个树,找到所有路径,所以递归函数不要返回值!

领悟一下遍历后用数组存储的过程

用append和pop来实现回溯

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

    def recursion(root, targetRes, tmp):
        if not root:
            return
        if not root.left and not root.right:
            if targetRes == 0:
                res.append(tmp[::])
            return
        
        if root.left:
            tmp.append(root.left.val)
            recursion(root.left, targetRes-root.left.val, tmp)
            tmp.pop()

        if root.right:
            tmp.append(root.right.val)
            recursion(root.right, targetRes-root.right.val, tmp)
            tmp.pop()
        return

    recursion(root, targetSum-root.val, [root.val])

    return res

递归在树中的应用

先搞懂回溯的过程再去看精简版的代码

理解回溯的逻辑

如果遇到不符合条件的,返回上一节点

要理解如何返回上一节点,即在结果中删去该节点

构造二叉树

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

中序:左中右 后序:左右中

【看视频理解思路】 6步

  1. 判断postorder为空
  2. postorder最后一个元素为中间节点
  3. 寻找inorder数组中切割点 index
  4. 切inorder 用中间节点
  5. 切postorder 用的是切好的inorder的左右区间长度
  6. 递归处理 左区间 右区间

注:先理解构建过程时要一步步切分左右区间

后序:最后一个节点一定是root,从而区分左右区间;划分好区间后,在后序中对应的最后一位就是中间节点

递归处理左区间右区间

优化:如果len==1,说明仅有一个节点

先得到的都是left,用后序的点在中序中定位,确定是否有左右节点

class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
        if not postorder:
            return

        # 第二步: 后序遍历的最后一个就是当前的中间节点
        root_val = postorder[-1]
        root = TreeNode(root_val)

        # 第三步: 找切割点.
        root_index = inorder.index(root_val)

        # 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
        left_inorder = inorder[:root_index]
        right_inorder = inorder[root_index + 1:]

        # 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
        # ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
        left_postorder = postorder[:len(left_inorder)]
        right_postorder = postorder[len(left_inorder): len(postorder) - 1]


        # 第六步: 递归
        root.left = self.buildTree(left_inorder, left_postorder)
        root.right = self.buildTree(right_inorder, right_postorder)

        # 第七步: 返回答案
        return root