1. 程式人生 > 其它 >力扣 leetcode 572. 另一棵樹的子樹

力扣 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 的深度優先搜尋序列的「子串」。