题目18:树的子结构(leetcode链接:https://leetcode-cn.com/problems/shu-de-zi-jie-gou-lcof/)
题目分析
在探讨这道题目之前,我们先来看一个类似的比较简单的题目:另一个树的子树(链接:https://leetcode-cn.com/problems/subtree-of-another-tree/)
判断另一个数的子树
这道题目要求树的子树要包含其所有子孙节点,因此我们可以遍历二叉树找到一个节点与所给子树中的根节点相等的节点,在判断以这个节点为根节点的子树是否与所给子树相等即可。那么,如何判断两颗二叉树是否相等呢?
判断两颗二叉树是否相等
任何一颗非空二叉树都可以分为根节点、左子树、右子树三部分,判断两颗二叉树是否相等就判断两颗二叉树对应的这三部分是否完全相等即可。而二叉树的根节点可以直接进行值的比较判断是否相等,左子树和右子树判断相等时又是判断树的相等问题,因此我们可以递归解决这个问题。
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
//判断结构是否相同
if(p == NULL && q == NULL){
//结构相同,返回true
return true;
}
if(p == NULL || q == NULL){
//结构不同,返回false
return false;
}
//判断值是否相同
if(p->val != q->val){
//值不同,返回false
return false;
}
//继续判断左右子树的结构和值是否也相同
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
};
有了判断两颗二叉树是否相同的程序,再来解决另一个树的子树问题:
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
//判断结构是否相同
if(p == NULL && q == NULL){
//结构相同,返回true
return true;
}
if(p == NULL || q == NULL){
//结构不同,返回false
return false;
}
//判断值是否相同
if(p->val != q->val){
//值不同,返回false
return false;
}
//继续判断左右子树的结构和值是否也相同
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
bool isSubtree(TreeNode* s, TreeNode* t) {
//首先,s不能为NULL
if(s == NULL){
return false;
}
//判断两棵树是否相等
if(isSameTree(s,t)){
//两棵树相等,返回true
return true;
}
//判断S的左右子树是否存在一个子结构与t相同
return isSubtree(s->left,t) || isSubtree(s->right,t);
}
};
回归题目,解决“树的子结构”问题
判断B是不是A的子结构可以分为一下两步完成:1)在树A中找到一个与B的根节点相同的节点R。2)判断树A中以R为根节点的子树是否包含B这样的子结构
面试小提示:二叉树相关的代码有大量的指针操作,每次使用指针时都要想清楚这个指针是否可能为NULL,如果为NULL我们又该如何解决。
代码描述
class Solution {
public:
bool hasSubTree(TreeNode* A,TreeNode* B){
//如果A为空,B不为空,返回false;如果B为空,返回true
if(B == NULL){
return true;
}
if(A == NULL){
return false;
}
//判断是否存在子结构
//如果根节点不同,则不存在。否则,判断左右子树
if(A->val != B->val){
return false;
}
return hasSubTree(A->left,B->left) && hasSubTree(A->right,B->right);
}
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(A == NULL || B == NULL){
//两棵树都不能为NULL
return false;
}
//在A中查找与B的根节点相同的节点
bool ret = false;
//判断根节点是否相同
if(A->val == B->val){
//判断是否存在这样的子结构
ret = hasSubTree(A,B);
}
//如果根节点不相同或者根节点相同但不存在这样的子结构,查找左右子树中是否存在与B相同的节点
if(!(ret)){
//在左子树中查找,如果找到就不在右子树中找,因此如果找到需要将ret变为true
ret = isSubStructure(A->left,B);
}
if(!(ret)){
//左子树中没有找到,继续在右子树中查找
ret = isSubStructure(A->right,B);
}
return ret;
}
};