题目:
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
拿到这个题目,我们应该定义什么情况下是子结构:
当B的头节点等于A的头节点,并且左右子树的头节点也相等,则返回true,否则我们在A的左子树或者A的右子树中继续判断:
看下面代码:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { if(pRoot1 == nullptr || pRoot2 == nullptr) return false;//边界处理 if(pRoot1->val == pRoot2->val && isequal(pRoot1,pRoot2)) return true; return HasSubtree(pRoot1->left,pRoot2) || HasSubtree(pRoot1->right,pRoot2); }
显然,第一行代码用于边界判断,第二行代码,就是如果头节点相等,且头节点下的子树节点也相等,那么是子结构
第三行代码就是在A的左子树或者A的右子数中寻找。
显然,仅仅有一个递归结构式不行的,还需要我们判断子树节点相等这一条件,显然这也是一个递归的过程,因为子树也有子树,见下面代码:
1 bool isequal(TreeNode* p1,TreeNode* p2)//完成对子树结构的判断 2 { 3 if(p2 == nullptr) return true; 4 if(p1 == nullptr) return false; 5 if(p1->val != p2->val) return false; 6 return isequal(p1->left,p2->left)&& isequal(p1->right,p2->right); 7 }
如果我们抛开,1,2行代码,上述显然是对子树判断的标准递归。若子树头节点不相等,则返回false。若相等,则要求左边和左边相等,右边和右边相等。
当然了,1,2行的边界很重要:第一行的边界表明了子树B到了末尾了,此时自然返回true(注意区别其与上一段代码的边界的区别),第二行代码表明了,p2没有到末尾,反而父树到了末尾,此时必然是不是子结构。