1 条题解
-
0
题目理解
我们需要在一棵给定的二叉树中,找到一个节点数最多的对称二叉子树。
对称二叉树的定义:
- 必须是二叉树
- 将树中所有节点的左右子树交换后,新树与原树在结构上完全相同,且对应节点的权值相等
注意:单节点树(只有树根)也是对称二叉树。
关键概念分析
1. 对称性的理解
对于一棵以节点 为根的二叉树,它是对称二叉树当且仅当:
- 根节点 的权值任意
- 的左子树与右子树是镜像对称的
更具体地说,如果设:
- 左子树为 ,右子树为
- 那么 和 必须满足:
- 的根节点权值 = 的根节点权值
- 的左子树 与 的右子树 对称
- 的右子树 与 的左子树 对称
2. 递归定义
用递归的方式定义对称性检查函数
is_symmetric(u, v):- 如果 和 都为空,返回真
- 如果 和 一个为空一个不为空,返回假
- 如果 和 的权值不相等,返回假
- 否则递归检查:
is_symmetric(u.left, v.right)且is_symmetric(u.right, v.left)
那么以 为根的树是对称二叉树当且仅当:
is_symmetric(r.left, r.right)
算法设计
1. 暴力解法(小数据)
最直接的方法是:
- 枚举每个节点作为候选子树的根
- 检查以该节点为根的子树是否对称
- 如果对称,记录节点数并更新最大值
复杂度分析:
- 枚举 个节点
- 每次检查对称性需要 ,其中 是子树大小
- 最坏情况下 ,对于 不可行
2. 优化思路
关键观察:如果一棵树是对称二叉树,那么它的左右子树必须结构相同。
我们可以利用这个性质进行剪枝:
- 在检查对称性时,如果发现子树大小不同,直接返回不对称
- 预处理每个节点的子树大小
3. 高效算法框架
-
预处理:
- 计算每个节点的子树大小
size[u] - 计算每个节点的子树哈希值(可选,用于快速比较)
- 计算每个节点的子树大小
-
对称性检查优化:
- 先比较左右子树的
size,如果不同则直接返回假 - 然后递归检查对称性
- 先比较左右子树的
-
遍历策略:
- 使用 DFS 遍历每个节点
- 对于每个节点,检查以其为根的子树是否对称
- 如果对称,用
size[u]更新答案
4. 哈希优化
对于大数据(),我们可以使用树哈希来加速对称性检查:
- 为每个子树计算一个哈希值
- 比较左右子树的哈希值来判断是否对称
- 但需要注意哈希冲突的可能性
哈希函数设计示例:
hash[u] = (val[u] * base^3 + hash[left] * base^2 + hash[right] * base + size[u]) % mod对称检查时,比较:
hash[left] 与 镜像哈希(right)其中镜像哈希是交换左右子树计算得到的哈希值。
特殊情况处理
1. 满二叉树和完全二叉树
对于测试点 9-16,树是满二叉树或完全二叉树,这大大简化了问题:
- 结构已知,对称性检查更简单
- 可以利用层次遍历的性质
2. 权值全为 1
对于测试点 17-20,所有节点权值都是 1:
- 只需要检查结构对称,不需要比较权值
- 进一步简化了问题
3. 边界情况
- 空节点的处理
- 单节点树(总是对称)
- 只有左子树或只有右子树的节点
算法步骤总结
- 读入数据:存储树的邻接表结构和节点权值
- 预处理子树大小:通过 DFS 计算每个节点的
size[u] - (可选)预处理哈希值:为大数据准备
- 检查对称性:对于每个节点,检查以其为根的子树是否对称
- 更新答案:如果对称,用
size[u]更新最大节点数
复杂度分析
- 预处理子树大小:
- 对称性检查:最坏情况下 ,但通过剪枝可以优化
- 实际表现:由于对称二叉树的限制很强,大部分子树很快就会被剪枝
实现技巧
- 记忆化:对于已经检查过的子树对,可以缓存结果
- 提前终止:在 DFS 过程中,如果当前子树大小已经小于当前最大答案,可以提前返回
- 层次剪枝:从底层往顶层检查,利用子树的对称性信息
总结
这道题的核心在于理解对称二叉树的递归定义,并通过合理的剪枝策略来优化算法:
- 问题本质:在二叉树中寻找最大的镜像对称子树
- 关键观察:对称性具有递归结构,左右子树必须互为镜像
- 优化策略:子树大小剪枝、哈希加速、记忆化
- 特殊情况:满二叉树、完全二叉树、权值均匀等情况可以特殊处理
通过深入分析对称性的性质,我们可以在较大的数据范围内高效地解决这个问题。这种"递归检查 + 剪枝优化"的思路在树形结构问题中非常常见且有效。
- 1
信息
- ID
- 5235
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者