[CareerCup] 4.8 Contain Tree 包含樹

Grandyang發表於2015-08-08

 

4.8 You have two very large binary trees: Tl, with millions of nodes, and T2, with hundreds of nodes. Create an algorithm to decide if T2 is a subtree of Tl. A tree T2 is a subtree of Tl if there exists a node n in Tl such that the subtree of n is identical to T2. That is, if you cut off the tree at node n, the two trees would be identical.

 

這道題給我們兩棵樹,T1和T2,其中T1有百萬個節點,T2有上百個節點,讓我們寫演算法來判斷T2是不是T1的子樹。首先可以用的方法是,我們對兩棵樹分別進行前序和中序遍歷,然後把結果分別存入字串中,如果T2的前序和中序遍歷的字串分別是T1的前序和中序遍歷的字串的子串,那麼我們可以判定T2是T1的子樹,參見程式碼如下:

 

解法一:

class Solution {
public:
    bool containTree(TreeNode *root1, TreeNode *root2) {
        string pre1, pre2, in1, in2;
        preorder(root1, pre1);
        preorder(root2, pre2);
        inorder(root1, in1);
        inorder(root2, in2);
        if (pre1.find(pre2) == pre1.size() - pre2.size() && in1.find(in2) == in1.size() - in2.size()) return true;
        else return false;
    }
    void preorder(TreeNode *root, string &res) {
        if (!root) return;
        res.append(to_string(root->val));
        preorder(root->left, res);
        preorder(root->right, res);
    }
    void inorder(TreeNode *root, string &res) {
        if (!root) return;
        inorder(root->left, res);
        res.append(to_string(root->val));
        inorder(root->right, res);
    }
};

 

但是上面這種解法存在例外情況無法正確分辨,比如下面的兩棵樹:

     3                       3

   /           and            \

3                                 3

它們的中序和前序遍歷都相同,所以上述演算法會返回true,但我們知道它們是兩個不同的樹,誰也不包含誰,誰也不是誰的子樹。Cracking the Coding Interview 5th Edition這書上第235頁上說我們可以標記處空節點,但這種方法麻煩,又佔空間,所以這裡我不去寫它。下面來看書上給出的另一種解法,這種解法的思路是,我們首先判斷T2是否為空,為空則直接返回True,因為空樹是任何樹的子樹,然後我們看T1是否為空,T1為空直接返回false,因為空樹不可能有非空子樹,然後我們看兩個根節點的值是否相同,如果相同,則呼叫matchTree方法,來比較整個T2樹,如果完全匹配則返回true,否則繼續往下遞迴,參見程式碼如下:

 

解法二:

class Solution {
public:
    bool containTree(TreeNode *root1, TreeNode *root2) {
        if (!root2) return true;
        if (!root1) return false;
        if (root1->val == root2->val) {
            if (matchTree(root1, root2)) return true;
        }
        return containTree(root1->left, root2) || containTree(root1->right, root2);
    }
    bool matchTree(TreeNode *root1, TreeNode *root2) {
        if (!root1 && !root2) return true;
        if (!root1 || !root2) return false;
        if (root1->val != root2->val) return false;
        else (matchTree(root1->left, root2->left) && matchTree(root1->right, root2->right));
    }
};

 

相關文章