代码随想录算法训练营 Day 14

3 minute read

Published:

Q1. LeetCode 513

思路 - 任何遍历方式都可以

保证了左子树优先遍历。注意需要找到的是最后一层的最左边节点

解法1. 递归+回溯

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        def dfs(node, depth):
            # 找到叶子节点
            if not node.left and not node.right:
                # 更新外部定义的变量,需要用到nonlocal关键字
                nonlocal max_depth, res
                if depth > max_depth:
                    max_depth = depth
                    res = node.val
                return

            if node.left:
                dfs(node.left, depth + 1)

            if node.right:
                dfs(node.right, depth + 1)

        max_depth = float('-inf')
        res = 0
        dfs(root, 0)

        return res

解法2: 迭代法

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        res = 0
        queue = deque([root])

        while queue:
            for i in range(len(queue)):
                curr = queue.popleft()
                # 层序遍历,最先推出的就是这一层最左边的节点
                if i == 0:
                    res = curr.val

                if curr.left:
                    queue.append(curr.left)

                if curr.right:
                    queue.append(curr.right)

        return res

Take some notes

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。(通常使用前序遍历)
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。(通常使用后序遍历)

Q2. LeetCode 112

思路 - 任何遍历方式都可以

解法1: 递归法

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        
        def dfs(node, s):
            if not node.left and not node.right:
                if s + node.val == targetSum:
                    return True
                else:
                    return False
            
            if node.left:
                if dfs(node.left, s + node.val):
                    return True
            
            if node.right:
                if dfs(node.right, s + node.val):
                    return True
            
            return False
        
        return dfs(root, 0)

解法2: 迭代法

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

        while stack:
            curr, s = stack.pop()
            if not curr.left and not curr.right:
                if s + curr.val == targetSum:
                    return True
            
            if curr.right:
                stack.append((curr.right, s + curr.val))
            
            if curr.left:
                stack.append((curr.left, s + curr.val))
        
        return False

Q3. LeetCode 113

思路 - 任何遍历方式都可以

解法1: 递归法

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

        def dfs(node, s):
            if not node.left and not node.right:
                path.append(node.val)
                if s + node.val == targetSum:
                    res.append(path[:])
                path.pop()
                return
            
            if node.left:
                path.append(node.val)
                dfs(node.left, s + node.val)
                path.pop()
            
            if node.right:
                path.append(node.val)
                dfs(node.right, s + node.val)
                path.pop()
            
            return
        
        dfs(root, 0)

        return res

解法2: 迭代法

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

        stack = [(root, 0, [])]

        while stack:
            curr, s, path = stack.pop()
            if not curr.left and not curr.right:
                path.append(curr.val)
                if s + curr.val == targetSum:
                    res.append(path[:])
                # path.pop()
            
            if curr.right:
                stack.append((curr.right, s + curr.val, path + [curr.val]))
            
            if curr.left:
                stack.append((curr.left, s + curr.val, path + [curr.val]))
        
        return res

Q4. LeetCode 106

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)

        # 根据中间节点划分中序遍历数组,前面为左子树,后面为右子树。先划分中序遍历能够得到左右子树的遍历长度
        separator_idx = inorder.index(root_val)

        inorder_left = inorder[:separator_idx]
        inorder_right = inorder[separator_idx + 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

Q5. LeetCode 105

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)

        separator_idx = inorder.index(root_val)

        inorder_left = inorder[:separator_idx]
        inorder_right = inorder[separator_idx + 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

总结

  1. 递归函数是否需要返回值:1). 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。2). 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。3). 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
  2. 前序和中序可以确定唯一二叉树,中序和后序也可以确定唯一二叉树,但前序和后序无法确定