力扣 leetcode 572. 另一棵树的子树

问题描述

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

提示:

  • root 树上的节点数量范围是 [1, 2000]
  • subRoot 树上的节点数量范围是 [1, 1000]
  • -10^4 <= root.val <= 10^4
  • -10^4 <= subRoot.val <= 10^4

示例

示例 1:

输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true

示例 2:

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false

解题思路

本题一个最简单的解法是遍历树一遍,然后每找到一个节点的 val 与 subTree 的 root 节点的 val 相同时,就判断一次树结构是否相同。代码如下:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        queue<TreeNode*> q;
        queue<TreeNode*> rt;
        queue<TreeNode*> st;
        TreeNode* r = nullptr;
        TreeNode* s = nullptr;
        q.emplace(root);
        TreeNode *tmp = nullptr;
        bool flag = true;
        while(!q.empty()){
            tmp = q.front();
            q.pop();
            if(tmp->val == subRoot->val){
                rt.emplace(tmp);
                st.emplace(subRoot);
                flag = true;
                while(!rt.empty() && !st.empty()){
                    r = rt.front();
                    rt.pop();
                    s = st.front();
                    st.pop();
                    if(r->left != nullptr && s->left != nullptr){
                        if(r->left->val == s->left->val){
                            rt.emplace(r->left);
                            st.emplace(s->left);
                        }
                        else{
                            flag = false;
                            break;
                        }
                    }
                    else if(r->left == s->left);
                    else{
                        flag = false;
                        break;
                    }
                    if(r->right != nullptr && s->right != nullptr){
                        if(r->right->val == s->right->val){
                            rt.emplace(r->right);
                            st.emplace(s->right);
                        }
                        else{
                            flag = false;
                            break;
                        }
                    }
                    else if(r->right == s->right);
                    else{
                        flag = false;
                        break;
                    }
                }
                if(flag && rt.empty() && st.empty()){
                    return true;
                }
                while(!rt.empty()){rt.pop();};
                while(!st.empty()){st.pop();};
            }
            if(tmp->left != nullptr){
                q.emplace(tmp->left);
            }
            if(tmp->right != nullptr){
                q.emplace(tmp->right);
            }
        }
        return false;
    }
};

可以看到,上面的代码非常复杂,且效率不高。那么更高效的算法是什么呢?我们注意到一棵子树上的点在深度优先搜索序列(即先序遍历)中是连续的。了解了这个之后,我们可以确定解决这个问题的方向就是:把 s 和 t 先转换成深度优先搜索序列,然后看 t 的深度优先搜索序列是否是 s 的深度优先搜索序列的「子串」。

posted @ 2022-12-05 14:13  greatestchen  阅读(8)  评论(0编辑  收藏  举报