(245)LintCode 之判定 T2 是否为 T1的子树

题目:有两个不同大小的二叉树:T1有上百万的节点;T2有好几百的节点。请设计一种算法,判定T2是否为T1的子树。

看到这道题目,我想起了二叉树的一个性质:如果两棵二叉树的中序遍历+前序遍历(或中序遍历+后续遍历)相同,可以确定这两个二叉树是一样的。所以可以将两棵树的中序遍历和前序遍历都求出来,然后用string.find()函数来确定T2的串是否是T1的子串。

但是题目强调了“T2有上百万个节点”,这样的话,将树转换为字符串未免空间复杂度太高了。所以这道题还是要用递归的方法来解决。

思路:①先判断边界条件

if(T2==NULL)
   return true;
if(T1==NULL)
   return false;//T2已经不是NULL,如果T1是NULL的话,说明T2不可能是T1的子树

②如果两棵树都不为空,遍历T1,查找有没有和T2的root相同的节点

③如果找到一个相同的结点node1,比较以这个节点为根的子树是否与T2完全相同

        if(完全相同) return true;

        else  node1的子树递归调用②;

③如果执行到T1的最后一个结点还没有返回,说明T1中没有和T2完全一样的子树,返回false;

代码实现如下(非常详细的注释):

class Solution {
public:
    /**
     * @param T1: The roots of binary tree T1.
     * @param T2: The roots of binary tree T2.
     * @return: True if T2 is a subtree of T1, or false.
     */
    
    /*判断T2是否是T1的子树*/
    bool isSubtree(TreeNode * T1, TreeNode * T2) {
        // write your code here
        if(T2==NULL){
            return true;
        }
        if(T1==NULL){
            return false;
        }
        /*T1和T2都不为空,调用自定义函数compare()判断T1是否包含T2*/
        return compare(T1,T2);
    }
    
    /*如果T1包含T2,返回true,否则返回false*/
    bool compare(TreeNode * T1, TreeNode * T2){
        //T1为空时,说明T1中所有的结点都确认过了,不包含T2
        if(T1==NULL){
            return false;
        }else{
            //找到一个相同的结点
            if(T1->val==T2->val){
                //match()判断这两棵树是否完全相等
                if(match(T1,T2)){
                    //如果完全相等,返回true,说明T1包含T2,算法结束。
                    return true;
                }
                //否则,什么也不做,继续找下一个相等的结点
            }
            //对T1的子树递归调用compare(),但凡找到一个符合的子树,就返回true,
            //结束算法
            if(compare(T1->left,T2)||compare(T1->right,T2)){
                return true;
            }
        }
        
    }
    
    /*递归判断T1,T2是否完全相等*/
    bool match(TreeNode * T1, TreeNode * T2){
        //如果都为空,则T1与T2相等
        if(T1==NULL&&T2==NULL){
            return true;
        }
        //如果一棵为空,一棵不为空,说明不相等
        if(T1==NULL||T2==NULL){
            return false;
        }
        //如果T1的根和T2的根不相等,说明两棵树不相等
        if(T1->val!=T2->val){
            return false;
        }
        //递归调用T1,T2的子树判断
        return match(T1->left,T2->left)&&match(T1->right,T2->right);
    }
};

————————————————————————————————————————————————————

本题与《(93)判断一棵树是否高度平衡》有一个类似的思想:本题中,找到“完全相同的子树”有一票肯定结果的作用。而(93)题的“不平衡子树”有一票否决的作用。在这种题目中,要格外注意,没有一票决定权的结果不能随便返回。

什么意思呢?就本题而言,当你在T1中找到了一个节点与T2的根节点相同,然后你开心地调用match()函数去判断这两棵树是否完全相等,如果它们完全相等的话,那太棒了,你可以确定T2是T1的子树了,直接返回true,工作完成。但是如果你遗憾地发现它们并不相等,这时候,你千万不能直接返回一个false,因为这样等于放弃了继续寻找其它子树,直接说“我找到了一棵很像的,但是并不等于T2,所以我觉得T2不是T1的子树,我放弃了”。你应该什么也不做,把苦咽下去,然后继续去寻找其它的节点。



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值