LeetCode-572:另一个树的子树

一、题目描述

在这里插入图片描述

二、解题思路

采用递归来解决:如果一个树是另一个树的子树,那么:

  • 主树和子树为同一棵树
  • 子树是主树的左子树的子树
  • 子树是主树的右子树的子树

那么我们可以得到如下代码:

class Solution {
private:
    bool isSametree(TreeNode* s, TreeNode* t) {
       if(!s && !t) return true;
       if(!s || !t) return false;
       return s && t && s->val == t->val && isSametree(s->left, t->left) && isSametree(s->right, t->right);
    }
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(!s && !t) return true;
        if(!s || !t) return false;
        return isSametree(s, t) || isSubtree(s->left, t) || isSubtree(s->right, t);
    }
};

我们来看一下运行结果
在这里插入图片描述
还不错?上面的是评论区最高票解答。
不得不说思路确实清晰,但是这可能并不是最快的解答方式。
我们来分析一下原因:这种方式相当于将主树遍历一遍,把每个节点都当做头节点,依次判断以主树中以当前节点为根节点的子树是否和主树完全相等。
乍一看如果主树当前节点和子树当前节点不相等的话,直接返回false,那就很容易判断出来了啊,也并不是很费时间啊?
但是这种方法真正的性能瓶颈在于,如果故意把主树设置成相当一部分主树的子树中的元素,只有很少几个和子树不同的话,那就需要重复地判断很多次,最差情况下(二叉树有相当一部分元素的值是相等的)甚至可以恶化到 O ( n 2 ) O(n^2)
怎么优化呢,下面是我自己写的代码

class Solution {
private:
    bool flag = 0;
    TreeNode* tmp ;
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(!flag){
            tmp = t;
            flag = true;
        }
        if(!s && !t)    return true;
        else if(!s || !t)    return false;
        if(s->val == t->val)
            return (isSubtree(s->left, t->left) && isSubtree(s->right, t->right)) || (isSubtree(s->left, t) || isSubtree(s->right, t));
        else{
            if(tmp != t)    return false;
            return isSubtree(s->left, t) || isSubtree(s->right, t);
        }
    }
};

先来看一下运行结果:内存消耗不少,但是运行很快。
在这里插入图片描述
我的代码的核心思想是,根据当前进行判断的子树节点是否为根节点来快速确定是否需要向下判断。

  • 首先,如果主树当前节点和子树当前节点相等,那么无论是否当前子树节点是否为子树根节点,主树的这棵子树都有可能成为匹配的树。同时不要忽略主树的当前节点的孩子节点仍然等于主树当前节点的值,在这种情况下主树的孩子节点将在下一轮递归中演变成本轮递归的当前主树节点,所以我们得到判断这种情况下的代码:
if(s->val == t->val)
    return (isSubtree(s->left, t->left) && 
    		isSubtree(s->right, t->right)) || 
    	   (isSubtree(s->left, t) || isSubtree(s->right, t));
  • 如果主树当前节点和子树当前节点不相等:核心思想
    • 如果子树当前的节点不是根节点,就说明已经排除了主树的当前节点的孩子节点可以成为匹配子树的可能:因为主树当前节点的孩子节点即使有可能成为匹配子树,那么主树当前节点的孩子节点也得是作为匹配子树的根节点,而子树当前的节点并不是根节点,所以根本不可能匹配成功,直接返回false
    • 如果子树当前的节点是根节点,那主树的当前节点与子树的根节点匹配不上说明不了什么问题,可能存在的匹配子树还可能隐藏在主树的当前节点的左右子树里,问题转化为对主树的当前节点的孩子节点作为主树下一轮判断的根节点。
    • 这种情况下的代码:
else{
    if(tmp != t)    return false;
    return isSubtree(s->left, t) || isSubtree(s->right, t);
}

三、解题代码

优化过的一行代码

class Solution {
private:
    bool flag = 0;
    TreeNode* tmp ;
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(!flag){
            tmp = t;
            flag = true;
        }
        return !s && !t ? true : !s || !t ? false : s->val == t->val ? (isSubtree(s->left, t->left) && isSubtree(s->right, t->right)) || (isSubtree(s->left, t) || isSubtree(s->right, t)) : tmp != t ? false : isSubtree(s->left, t) || isSubtree(s->right, t);
    }
};

四、运行结果

多行代码
在这里插入图片描述
一行代码
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44587168/article/details/105964004