Check Subtree:设T1
和T2
是两个非常大的二叉树,并且T1
比T2
大,判断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);
}
};