剑指offer——判断B树是否是A树的子结构

题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

一道蛮有意思的题,一开始理解错题意了,只考虑了B树完全覆盖了A中某棵子树,并且以为一定存在根节点相同就完全匹配B树的子树。然后想着只要从A树根节点往下遍历直到找到一个节点与B的根节点匹配即可。。。。还是想的太简单。

正确的题意是,再给出的A树中,任意一个部分,一段子树,该子树不一定延伸到叶子节点,这段子树与B树完全匹配,那么就不止是根节点的匹配,找到匹配的根节点后再继续使得两棵树的指针同时下移,一个一个比较该子树的每个节点是否都与B树相同

有一个不同即放弃以该根节点形成的子树。

在这里插入图片描述

如图所示,A树的根节点8是与B树根节点相同的,但其子树并不完全与B树相同,再者,A树左子树中有一部分与B树完全相同,但是并不是整颗子树完全相同,仅仅是一部分,那么就要从中挑出来与B树进行一一比对。

首先想到的思路即,递归查找A树中是否有某个节点的值与B树根节点一样,若一样,则认为该节点形成的子树可能包含了B,于是进入judge函数中,同时移动两棵子树上的指针,一一判断左右儿子的节点是否相同,相同则继续比较,不同直径返回false,另找其他的可能匹配的根节点。

如何判断其完全匹配,对于正在两棵树上同时移动的指针来说,若B指向的节点不存在了,那么说明B已经遍历完了该条路径上的所有节点,并且没有与A指向节点不同的值。可以返回true,表示该路径匹配。如果A指向的节点不存在了,而B指向的节点存在,那么直接返回false,因为这种情况明显是B有值而A没值,匹配不成功,第三种情况就是两者都有值,比较值是否相等即可。如果相等,同时再向左右儿子扩展匹配。

代码如下:

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    bool judge(TreeNode* root1,TreeNode* root2)
    {
        if(root2==NULL)return true;//B树节点不存在了,比较完成,没有出错
        if(root1==NULL)return false;//A树节点不存在,而B树节点存在,匹配失败
        if (root1->val!=root2->val)return false;//同时存在,但值不同,匹配失败
        else return judge(root1->left,root2->left)&&judge(root1->right,root2->right);//同时存在且匹配成功,那么同时向左右儿子扩展比较
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(pRoot1==NULL||pRoot2==NULL)return false;//题目已经说明,存在空树则不是子结构
        else return judge(pRoot1,pRoot2)||HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2);//这里三个函数都要调用,不能因为判断了某个节点值相等就只调用一个judge函数,而不调用扩展函数,这样会导致匹配失败一次即全盘判定失败
    }
};
posted @ 2018-12-11 14:06  KuroNekonano  阅读(858)  评论(0编辑  收藏  举报