📜  面试中的 50 大树编码问题(1)

📅  最后修改于: 2023-12-03 15:28:53.300000             🧑  作者: Mango

面试中的 50 大树编码问题

在面试时,树是最常见的数据结构之一,因此树编码问题也是面试过程中必考的题目之一。本文总结了 50 个树编码问题并提供了详细的解释和代码实现,希望能够帮助程序员加强对树的理解和编码能力。

1. 树遍历
1.1 先序遍历

先序遍历是指先遍历节点本身,然后递归地遍历左右子树。常用于生成一个与树结构相同的表达式。

实现

def preorder_traversal(root):
    if not root:
        return []
    stack, res = [root], []
    while stack:
        node = stack.pop()
        res.append(node.val)
        if node.right:
            stack.append(node.right)
        if node.left:
            stack.append(node.left)
    return res

示例

给定二叉树[1,2,3,None,4,5,6],先序遍历结果为[1,2,None,4,5,None,None,3,None,6,None,None]

1.2 中序遍历

中序遍历是指先递归地遍历左子树,然后遍历节点本身,最后递归地遍历右子树。在二叉搜索树上使用中序遍历可以得到有序的结果。

实现

def inorder_traversal(root):
    if not root:
        return []
    stack, res = [], []
    while stack or root:
        while root:
            stack.append(root)
            root = root.left
        node = stack.pop()
        res.append(node.val)
        root = node.right
    return res

示例

给定二叉树[1,2,3,None,4,5,6],中序遍历结果为[2,4,None,None,5,None,None,1,3,6,None,None,None]

1.3 后序遍历

后序遍历是指先递归地遍历左右子树,然后遍历节点本身。常用于先处理子节点,后处理父节点的情形。

实现

def postorder_traversal(root):
    if not root:
        return []
    stack, res = [root], []
    while stack:
        node = stack.pop()
        res.append(node.val)
        if node.left:
            stack.append(node.left)
        if node.right:
            stack.append(node.right)
    return res[::-1]

示例

给定二叉树[1,2,3,None,4,5,6],后序遍历结果为[4,None,5,None,2,6,None,None,3,1]

2. 树的遍历序列还原

给定树的前序/中序/后序遍历序列,如何重建二叉树?

2.1 由前序和中序遍历序列还原二叉树
实现
def build_tree(preorder, inorder):
    if not preorder or not inorder:
        return None
    root_val = preorder[0]
    root = TreeNode(root_val)
    idx = inorder.index(root_val)
    root.left = build_tree(preorder[1:1 + idx], inorder[:idx])
    root.right = build_tree(preorder[1 + idx:], inorder[idx + 1:])
    return root

示例

给定树的前序遍历序列[1,2,4,5,3,6]和中序遍历序列[4,2,5,1,3,6],还原二叉树。

2.2 由中序和后序遍历序列还原二叉树

实现

def build_tree(inorder, postorder):
    if not postorder or not inorder:
        return None
    root_val = postorder[-1]
    root = TreeNode(root_val)
    idx = inorder.index(root_val)
    root.left = build_tree(inorder[:idx], postorder[:idx])
    root.right = build_tree(inorder[idx + 1:], postorder[idx:-1])
    return root

示例

给定树的中序遍历序列[4,2,5,1,3,6]和后序遍历序列[4,5,2,6,3,1],还原二叉树。

2.3 根据先序遍历和后序遍历重建二叉树

实现

由于先序遍历顺序为[root, left, right],而后序遍历顺序为[left, right, root],因此可以递归地构建二叉树。

def construct_from_pre_post(pre, post):
    if not pre:
        return None
    root = TreeNode(pre[0])
    if len(pre) == 1:
        return root
    L = post.index(pre[1]) + 1
    root.left = construct_from_pre_post(pre[1:L + 1], post[:L])
    root.right = construct_from_pre_post(pre[L + 1:], post[L:-1])
    return root

示例

给定树的先序遍历序列[1,2,4,5,3,6]和后序遍历序列[4,5,2,6,3,1],还原二叉树。

3. 树的路径问题
3.1 从根到叶的所有路径

给定一颗二叉树,返回所有从根到叶的路径。

实现

def binary_tree_paths(root):
    if not root:
        return []
    if not root.left and not root.right:
        return [str(root.val)]
    paths = []
    if root.left:
        for path in binary_tree_paths(root.left):
            paths.append(str(root.val) + '->' + path)
    if root.right:
        for path in binary_tree_paths(root.right):
            paths.append(str(root.val) + '->' + path)
    return paths

示例

给定二叉树[1,2,3,None,5],所有从根到叶的路径为['1->2->5', '1->3']

3.2 二叉树中的最大路径和

给定一个非空的二叉树,找到连接树中节点的最大路径和。路径可以以任意顺序访问,但需要按照从父节点到子节点的方向。

实现

def max_path_sum(root):
    def dfs(node):
        if not node:
            return 0
        left = max(dfs(node.left), 0)
        right = max(dfs(node.right), 0)
        nonlocal max_sum
        max_sum = max(max_sum, left + node.val + right)
        return max(left, right) + node.val
    max_sum = float('-inf')
    dfs(root)
    return max_sum

示例

给定二叉树[1,2,3],最大路径和为6

4. 二叉搜索树问题
4.1 验证二叉搜索树

判断一个二叉树是否是二叉搜索树。

实现

def is_valid_bst(root):
    def inorder_traversal(node, inorder):
        if not node:
            return inorder
        inorder = inorder_traversal(node.left, inorder)
        inorder.append(node.val)
        inorder = inorder_traversal(node.right, inorder)
        return inorder
    inorder = inorder_traversal(root, [])
    return inorder == sorted(list(set(inorder)))

示例

给定二叉树[2,1,3],是二叉搜索树;给定二叉树[5,1,4,None,None,3,6],不是二叉搜索树。

4.2 插入/删除节点

向一个二叉搜索树中插入和删除节点。

实现

class TreeNode:
    def __init__(self, val=None, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class BST:
    def __init__(self):
        self.root = None

    def insert(self, val):
        def helper(node, val):
            if not node:
                return TreeNode(val)
            if node.val > val:
                node.left = helper(node.left, val)
            else:
                node.right = helper(node.right, val)
            return node
        self.root = helper(self.root, val)

    def delete(self, val):
        def get_successor(node):
            node = node.right
            while node.left:
                node = node.left
            return node

        def delete_helper(node, val):
            if not node:
                return None
            if node.val == val:
                if not node.left and not node.right:
                    return None
                if not node.left:
                    return node.right
                if not node.right:
                    return node.left
                successor = get_successor(node)
                node.val = successor.val
                node.right = delete_helper(node.right, successor.val)
            elif node.val > val:
                node.left = delete_helper(node.left, val)
            else:
                node.right = delete_helper(node.right, val)
            return node

        self.root = delete_helper(self.root, val)

示例

插入节点到二叉搜索树,并删除一个节点。

5. 平衡二叉树问题
5.1 判断平衡二叉树

判断一个二叉树是否平衡,即左右子树高度差不能超过 1。

实现

def is_balanced(root):
    def helper(node):
        if not node:
            return 0
        left_height = helper(node.left)
        right_height = helper(node.right)
        nonlocal balanced
        if abs(left_height - right_height) > 1:
            balanced = False
        return max(left_height, right_height) + 1

    balanced = True
    helper(root)
    return balanced

示例

给定二叉树[3,9,20,None,None,15,7],是平衡二叉树;给定二叉树[1,2,2,3,3,None,None,4,4],不是平衡二叉树。

5.2 从有序数组构建平衡二叉搜索树

从一个有序数组中构造一颗高度平衡的二叉搜索树。

实现

def sorted_array_to_bst(nums):
    def helper(left, right):
        if left > right:
            return None
        mid = (left + right) // 2
        node = TreeNode(nums[mid])
        node.left = helper(left, mid - 1)
        node.right = helper(mid + 1, right)
        return node
    return helper(0, len(nums) - 1)

示例

给定有序数组[-10,-3,0,5,9],构建一颗平衡二叉搜索树。

6. N-ary Tree
6. 1 N-ary Tree Traversal

N 叉树是指每个节点有零个或多个子节点的树。实现 N 叉树的遍历。

实现

class Node:
    def __init__(self, val=None, children=[]):
        self.val = val
        self.children = children

def pre_order(root):
    if not root:
        return []
    stack, res = [root], []
    while stack:
        node = stack.pop()
        res.append(node.val)
        stack += node.children[::-1]
    return res

def post_order(root):
    if not root:
        return []
    stack1, stack2 = [root], []
    while stack1:
        node = stack1.pop()
        stack2.append(node.val)
        stack1 += node.children
    return stack2[::-1]

def level_order(root):
    if not root:
        return []
    queue, res = [root], []
    while queue:
        level = []
        for _ in range(len(queue)):
            node = queue.pop(0)
            level.append(node.val)
            queue += node.children
        res.append(level)
    return res

示例

给定 N 叉树[1,None,3,2,4,None,5,6],执行先序遍历、后序遍历和层序遍历,分别得到结果[1,3,5,6,2,4]、[5,6,3,2,4,1]和[[1], [3,2,4], [5,6]]