代码随想录算法训练营day18 | 513.找树左下角的值、112. 路径总和、106.从中序与后序遍历序列构造二叉树

513.找树左下角的值

找最底层、最左边的值

  • 迭代法找起来非常方便,可以按层序遍历,找到最后一层的第一个元素
  • 递归法的话不是说一直找左节点就可以找到,因为要找到的是最后一层,所以要找到深度最大最左边的元素。在递归时先遍历左子树(前中后序都可实现),根据深度进行更改
迭代法

层序遍历的模板,稍微更改一下即可

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        from collections import deque
        if not root:
            return 0
        queue = deque()
        queue.append(root)
        result = 0
        while queue:
            for i in range(len(queue)):
                node = queue.popleft()
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
                if i == 0:
                    result = node.val
        return result
递归法

递归三部曲

  1. 参数为当前节点,当前的深度,根节点深度为0;返回值不需要,但是需要定义一个全局的结果值和深度值
  2. 终止条件:如果当前节点为空,返回(不需要,因为单层逻辑中已经判断是否为空了,不为空才可以遍历);如果当前节点为叶子节点,比较深度值,如果大,则更新结果值
  3. 单层逻辑:如果当前节点有左节点,则继续递归左节点,如果当前节点有右节点,则继续遍历右节点
class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        self.result = 0
        self.max_depth = float('-inf')
        self.traversal(root, 0)
        return self.result

    def traversal(self, node, depth):
        if not node.left and not node.right:
            if depth > self.max_depth:
                self.result = node.val
                self.max_depth = depth
            return
        if node.left:
            self.traversal(node.left, depth+1)
        if node.right:
            self.traversal(node.right, depth+1)

112. 路径总和

递归三部曲

  1. 参数为当前节点,计数器;返回值为是否存在
  2. 终止条件:如果当前节点为叶子节点,且计数器为0,则返回True;如果当前节点为叶子节点,计数器不为0,则返回False
  3. 单层逻辑:如果当前节点的左节点存在,则遍历左节点;如果当前节点的右节点存在,则遍历右节点。需要注意一点,遇见满足条件的才返回True,返回False的值先不考虑,最后才返回False
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        return self.traversal(root, targetSum-root.val)

    def traversal(self, node, count):
        if not node.left and not node.right:
            return True if count == 0 else False
        if node.left:
            if self.traversal(node.left, count-node.left.val):
                return True
        if node.right:
            if self.traversal(node.right, count-node.right.val):
                return True
        return False

精简版的代码是不要求判断当前节点是否存在才能迭代的,直接有判断为空则返回False

class Solution:
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:
            return False
        if not root.left and not root.right and sum == root.val:
            return True
        return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)
  
路径总和II

求出所有满足条件的路径,因为要遍历整棵树,找到所有路径,不需要返回值

以 Python 语言为例,记录路径时若直接执行 res.append(path) ,则是将此 path 对象加入了 res ;

后续 path 改变时, res 中的 path 对象也会随之改变,因此无法实现结果记录。正确做法为:list(path)或者path[:]

感想:Python的引用与拷贝还需要学习

下面为错误的,可以看看注释中出现的结果

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        self.result = []
        self.path = []
        if not root:
            return self.result
        self.path.append(root.val)
        self.traversal(root, targetSum-root.val)
        print(self.result)
        # [[5], [5]]
        return self.result

    def traversal(self, node, count):
        if not node.left and not node.right:
            if count == 0:
                self.result.append(self.path)
                print(self.path, self.result)
                # [5, 4, 11, 2] [[5, 4, 11, 2]]
        # [5, 8, 4, 5] [[5, 8, 4, 5], [5, 8, 4, 5]]
            else:
                return
        if node.left:
            self.path.append(node.left.val)
            self.traversal(node.left, count-node.left.val)
            self.path.pop()
        if node.right:
            self.path.append(node.right.val)
            self.traversal(node.right, count-node.right.val)
            self.path.pop()

正确的做法

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        self.path = []
        self.result = []
        if not root:
            return self.result
        self.path.append(root.val)
        self.traversal(root, targetSum-root.val)
        return self.result

    def traversal(self, node, count):
        if not node.left and not node.right:
            if count == 0:
                self.result.append(self.path[:])
            else:
                return
        if node.left:
            self.path.append(node.left.val)
            self.traversal(node.left, count-node.left.val)
            self.path.pop()
        if node.right:
            self.path.append(node.right.val)
            self.traversal(node.right, count-node.right.val)
            self.path.pop()

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

中序遍历和后序遍历构建二叉树

  1. 如果后序遍历无元素,返回空
  2. 后序遍历的最后一个元素为根节点
  3. 根据根节点分割中序遍历,分为中序遍历的左子树和右子树
  4. 根据中序遍历分割的左右子树的长度,分割得到后序遍历的左右子树
  5. 根据分割的中序和后序的左右子树,再去递归
  6. 返回根节点
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)

        sep_index = inorder.index(root_val)
        inorder_left = inorder[:sep_index]
        inorder_right = inorder[sep_index+1:]

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

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

        return root

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