剑指 Offer 26. 树的子结构
难度中等
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:
给定的树 B:
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例 1:
输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1]
输出:true
限制:
0 <= 节点个数 <= 10000
#### 思路1.0:
列出A和B的先序遍历序列Avec,Bvec,同时在这个序列中记录每次遍历访问的节点,然后检验Avec中是否包含Bvec。
因为是先序遍历,所以Bvec的第一个元素即为他的根,如果A包含B,那么在Avec中即可找到以Bvec[0]为起点,Bvec[lenB-1]的子序列,且Bvec中的元素在Avec中出现的次序一致。
通过以上条件的Avec子序列,再遍历得到他的中序,后序遍历序列,拿来根Bvec的中序,后序序列对比。(空间复杂度有点高)。
思路2.0(已看题解):
先序遍历找到A中与B的根节点相同的节点,这里跟大部分题解都是相同的,就是后序判断的处理有些不同,自己是通过验证两棵树的三种遍历序列是否符合要求,而题解中的大佬们都是直接从两个点开始一起往下递归(即B的根节点,和之前找到的A中与B根节点相等的节点)。
判断条件:
TnodeA == NULL && TnodeB == NULL,true
TnodeA == NULL || TnodeB == NULL,false
代码1.0:
class Solution {
public:
void PreOrder(TreeNode* Tnode, const int& findVal, TreeNode* findNode)
{
if (Tnode != NULL)
{
if (Tnode->val == findVal)
{
findNode = new TreeNode(Tnode->val, Tnode->left, Tnode->right);
}
PreOrder(Tnode->left, findVal, findNode);
PreOrder(Tnode->right, findVal, findNode);
}
}
bool isMatching(TreeNode* A, TreeNode* B)
{
if (A == NULL && B == NULL) return true;
if (A == NULL || B == NULL) return false;
return ((A->val == B->val) && isMatching(A->left, B->left) && isMatching(A->right, B->right));
}
bool isSubStructure(TreeNode* A, TreeNode* B) {
TreeNode* Aroot;
PreOrder(A, B->val, Aroot);
return isMatching(Aroot, B);
}
};
运行错误,debug发现自己这里,找到与Broot值相等的A树节点这一步写的不对。(为啥???)
代码2.0:
class Solution {
public:
bool isMatching(TreeNode* A, TreeNode* B)
{
if (B == NULL) return true;
if (A == NULL) return false;
return ((A->val == B->val) && isMatching(A->left, B->left) && isMatching(A->right, B->right));
}
bool isSubStructure(TreeNode* A, TreeNode* B) {
if (A == NULL||B=NULL) return false;
return isMatching(A, B) || isSubStructure(A->left, B) || isSubStructure(A->right, B);
}
};
进行两层递归,一层在找A中与B根节点相等的节点,一层判断以该节点为根节点的A是否与B匹配