子树匹配要求目标树与原树某子树完全一致,即节点值、结构及递归关系严格相等;子结构匹配则只需目标树是原树中连通的一部分,允许b不占满对应子树(如b为空时直接返回true,而子树匹配要求两端同时为空)。

什么是子树匹配,和子结构匹配有什么区别
子树匹配(Subtree Match)要求目标树完全等于某棵子树:节点值、左右子树结构、递归关系都严格一致。而子结构匹配(Substructure Match)允许目标树是原树中“连通的一部分”,但不强制占据整个子树根——比如 isSubtree 函数通常指前者,isSubStructure(剑指 Offer 26)才是后者。
实际写代码前先确认需求:
- 如果题干说“判断
B是否为A的子树”,用严格子树匹配; - 如果说“判断
B是否为A的子结构”,就要允许B只匹配A中某个向下延伸的连通片段(B的根不一定对应A的某个完整子树根); - 常见坑:把
isSubStructure错写成只调用一次sameTree,漏掉对A所有节点的遍历尝试。
用 sameTree + DFS 实现 isSubtree(严格子树匹配)
核心思路是:对树 A 每个节点,检查以它为根的子树是否与 B 完全相同。不能只比根节点值,必须递归比结构+值。
关键点:
-
sameTree要处理空指针边界:if (!a && !b) return true; if (!a || !b) return false;; - 主函数
isSubtree在当前节点匹配失败时,要继续递归检查root->left和root->right; - 不要提前在根节点值不等时返回
false,因为子树可能在下层; - 示例逻辑:
bool isSubtree(TreeNode* root, TreeNode* subRoot) { if (!root) return false; if (sameTree(root, subRoot)) return true; return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); }
isSubStructure 的特殊逻辑:B 可不占满 A 的子树
剑指 Offer 26 的 isSubStructure 允许 B 是 A 中某路径上的连续片段。例如 A 根为 3,左子为 4,右子为 5;B 只有单节点 4 —— 此时应返回 true,即使 A 中节点 4 还有左右子(B 不关心它们是否存在)。
实现要点:
-
match函数(类似sameTree)需改为:当B为空时直接返回true(B匹配完了),而不是要求A也为空; - 对应地,
if (!b) return true; if (!a) return false;; - 主函数仍需遍历
A所有节点,但一旦match(a, b)成功就返回true; - 常见错误:把
match写成和sameTree一样逻辑,导致B为空时返回false。
性能与边界问题提醒
- 时间复杂度最坏
O(m * n)(m, n 分别为两树节点数),因为每个 A 节点都可能触发一次完整 B 遍历;
- 空树处理必须明确:
isSubtree(nullptr, non_null) → false,isSubtree(non_null, nullptr) → false(空树不是任何非空树的子树);但 isSubStructure(A, nullptr) 应返回 false(题目约定空树不是子结构);
- 指针比较前务必判空,否则
root->val 在 root == nullptr 时崩溃;
- 如果树深度大,递归可能栈溢出,生产环境要考虑迭代 DFS 或限制深度。
O(m * n)(m, n 分别为两树节点数),因为每个 A 节点都可能触发一次完整 B 遍历; isSubtree(nullptr, non_null) → false,isSubtree(non_null, nullptr) → false(空树不是任何非空树的子树);但 isSubStructure(A, nullptr) 应返回 false(题目约定空树不是子结构); root->val 在 root == nullptr 时崩溃; 真正容易被忽略的是:子结构匹配中 B 的空节点不约束 A 对应位置——这和子树匹配的“结构完全一致”有本质差别,写错一个判空条件,整题就过不了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











