程序员面试金典 4.10

Check Subtree:设T1T2是两个非常大的二叉树,并且T1T2大,判断T2是否是T1的一个子树。

比较直观的解法是对树进行遍历,判断遍历后得到的线性结果是否存在包含关系,但是不能使用中序遍历,应该使用先序遍历。即使是先序遍历,也会存在树结构不同但是结果相同的情况,所以也需要一些修正。写了前面几道题后可以发现,力扣上的测试用例全部都是使用层次遍历的方式表示一棵树,并将不存在的节点标记为null,因此这样是可以唯一定义一棵树的,推广到先序遍历也是一样的。这种方法的时间复杂度和空间复杂度为O(T1 + T2)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool checkSubTree(TreeNode* t1, TreeNode* t2) {
        ostringstream oss1, oss2;
        preOrder(t1, oss1);
        preOrder(t2, oss2);
        return oss1.str().find(oss2.str()) != string::npos;
    }
private:
    void preOrder(TreeNode* root, ostringstream &oss)
    {
        if(root == nullptr){
            oss << "n" << endl;
            return;
        }
        else oss << root->val << endl;
        preOrder(root->left, oss);
        preOrder(root->right, oss);        
    }
};

为了节省一些空间,可以遍历较大的树T1,一旦在T1中找到了和T2相等的节点(节点值相等,而不是同一块内存),就同时遍历这棵子树和T2,时间复杂度为O(nm)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool checkSubTree(TreeNode* t1, TreeNode* t2) {
        if(t2 == nullptr) return true;
        else if(t1 == nullptr) return false;
        else if(t1->val == t2->val && matchTree(t1, t2)) return true;
        else return checkSubTree(t1->left, t2) || checkSubTree(t1->right, t2);
    }
    bool matchTree(TreeNode* t1, TreeNode* t2)
    {
        if(t1 == nullptr && t2 == nullptr) return true;
        else if(t1 == nullptr || t2 == nullptr) return false;
        else if(t1->val != t2->val) return false;
        else return matchTree(t1->left, t2->left) && matchTree(t1->right, t2->right);
    }
};

你可能感兴趣的:(《程序员面试金典》)