蓝桥杯备战资料从0开始!!!(python B组)(最全面!最贴心!适合小白!蓝桥云课)树形数据结构

注:你的关注,点赞,评论让我不停更新

一、树的存储与遍历进阶

1. 邻接表存储优化
  • 动态构建树

    :对于输入为边列表的题目,可通过字典快速构建树结构:

    n = int(input())
    tree = [[] for _ in range(n)]
    for _ in range(n-1):
        u, v = map(int, input().split())
        tree[u].append(v)
        tree[v].append(u)  # 无向树需双向添加
  • 父子关系明确化

    :通过 BFS 或 DFS 遍历确定父节点,避免重复访问:

    from collections import deque
    parent = [-1] * n
    visited = [False] * n
    q = deque([0])
    visited[0] = True
    while q:
        u = q.popleft()
        for v in tree[u]:
            if not visited[v]:
                visited[v] = True
                parent[v] = u
                q.append(v)
2. 遍历算法对比
算法 实现方式 适用场景 时间复杂度
DFS 递归 / 栈 路径查找、连通性判断 O(N)
BFS 队列 最短路径、层次遍历 O(N)
迭代 DFS 显式维护栈 避免递归深度限制 O(N)

迭代 DFS 示例

def dfs_iterative(root):
    stack = [(root, False)]
    while stack:
        node, visited = stack.pop()
        if visited:
            print(node.val)  # 后序遍历
        else:
            stack.append((node, True))
            # 前序遍历:处理逻辑放在这里
            if node.right: stack.append((node.right, False))
            if node.left: stack.append((node.left, False))
            # 中序遍历:处理逻辑放在左右子树之间

二、树形 DP 深度解析

1. 状态转移方程设计
  • 选与不选问题

    def dfs(node):
        if not node:
            return (0, 0)  # (不选当前节点的最大值, 选当前节点的最大值)
        left_not, left_yes = dfs(node.left)
        right_not, right_yes = dfs(node.right)
        # 不选当前节点:子节点可选可不选
        not_choose = max(left_not, left_yes) + max(right_not, right_yes)
        # 选当前节点:子节点必须不选
        choose = node.val + left_not + right_not
        return (not_choose, choose)
  • 多状态扩展:若题目有多个约束条件(如距离限制),可增加状态维度。

2. 典型例题:蓝桥杯 2023 年省赛《种树》
  • 题目大意:在一条直线上种树,每个位置可选择种树或不种,相邻位置不能同时种树。求最大收益。

  • 解法

    :将问题转化为链式树(每个节点只有一个子节点),使用树形 DP:

    n = int(input())
    cost = list(map(int, input().split()))
    # dp[i][0]: 第i个位置不种的最大收益
    # dp[i][1]: 第i个位置种的最大收益
    dp = [[0]*2 for _ in range(n)]
    dp[0][1] = cost[0]
    for i in range(1, n):
        dp[i][0] = max(dp[i-1][0], dp[i-1][1])
        dp[i][1] = dp[i-1][0] + cost[i]
    print(max(dp[-1]))

三、特殊树结构应用

1. 字典树(Trie)优化
  • 字符串统计

    :统计所有单词的公共前缀:

    class TrieNode:
        __slots__ = ['children', 'count']  # 减少内存占用
        def __init__(self):
            self.children = {}
            self.count = 0
    ​
    def longest_common_prefix(strs):
        root = TrieNode()
        for word in strs:
            node = root
            for char in word:
                if char not in node.children:
                    node.children[char] = TrieNode()
                node = node.children[char]
                node.count += 1
        # 遍历Trie,找到所有节点count等于单词数量的路径
        prefix = []
        node = root
        while len(node.children) == 1 and node.count == len(strs):
            char = next(iter(node.children))
            prefix.append(char)
            node = node.children[char]
        return ''.join(prefix)
2. 二叉搜索树(BST)性质
  • 中序遍历有序性

    :将 BST 转换为有序数组,解决第 K 小问题:

    def kth_smallest(root, k):
        inorder = []
        stack = []
        while stack or root:
            while root:
                stack.append(root)
                root = root.left
            root = stack.pop()
            inorder.append(root.val)
            k -= 1
            if k == 0:
                return root.val
            root = root.right

四、LCA 算法优化与应用

1. 倍增法求 LCA
  • 预处理

    :每个节点的 2^k 级祖先,适用于多次查询:

    LOG = 20
    parent = [[-1]*n for _ in range(LOG)]
    depth = [0]*n
    ​
    # BFS预处理父节点和深度
    q = deque([root])
    parent[0][root] = -1
    while q:
        u = q.popleft()
        for v in tree[u]:
            if parent[0][v] == -1 and v != parent[0][u]:
                parent[0][v] = u
                depth[v] = depth[u] + 1
                q.append(v)
    ​
    # 预处理倍增表
    for k in range(1, LOG):
        for v in range(n):
            if parent[k-1][v] != -1:
                parent[k][v] = parent[k-1][parent[k-1][v]]
    ​
    def lca(u, v):
        if depth[u] < depth[v]:
            u, v = v, u
        # 提升u到与v同一深度
        for k in range(LOG-1, -1, -1):
            if depth[u] - (1 << k) >= depth[v]:
                u = parent[k][u]
        if u == v:
            return u
        # 同时提升u和v
        for k in range(LOG-1, -1, -1):
            if parent[k][u] != -1 and parent[k][u] != parent[k][v]:
                u = parent[k][u]
                v = parent[k][v]
        return parent[0][u]
2. 例题:蓝桥杯 2022 年省赛《树上的距离》
  • 问题:给定一棵树,求两节点间的距离。

  • 解法:利用 LCA 公式 distance(u, v) = depth[u] + depth[v] - 2*depth[lca(u, v)]

五、综合实战技巧

1. 树的序列化与反序列化
  • 层序遍历序列化

    def serialize(root):
        if not root:
            return "[]"
        queue = [root]
        res = []
        while queue:
            node = queue.pop(0)
            if node:
                res.append(str(node.val))
                queue.append(node.left)
                queue.append(node.right)
            else:
                res.append("null")
        # 去除末尾的null
        while res and res[-1] == "null":
            res.pop()
        return "[" + ",".join(res) + "]"
2. 树形 DP 与记忆化搜索
  • 记忆化搜索优化递归

    from functools import lru_cache
    class Solution:
        def maxPathSum(self, root: TreeNode) -> int:
            self.max_sum = -float('inf')
            @lru_cache(maxsize=None)
            def dfs(node):
                if not node:
                    return 0
                left = max(dfs(node.left), 0)
                right = max(dfs(node.right), 0)
                current_sum = node.val + left + right
                self.max_sum = max(self.max_sum, current_sum)
                return node.val + max(left, right)
            dfs(root)
            return self.max_sum

六、常见错误与调试技巧

  1. 循环引用问题:避免在树节点中存储父节点时形成环。

  2. 递归深度超限:改用迭代或设置 sys.setrecursionlimit(1 << 25)

  3. 边界条件遗漏:空树、单节点树的处理。

  4. 时间复杂度优化:使用邻接表而非邻接矩阵,减少空间消耗。

你可能感兴趣的:(蓝桥杯,python,数据结构)