啊这个题如果用暴力做法的话就是枚举s中的节点然后和t的根结点比较,找到后再进行两棵树的遍历去判断是否相等。如1所示,这样做的时间复杂度为O( | s | x | t | ),空间复杂度为O(max{d_s, d_t}),d表示树的深度。 |
另外一种方法是在DFS序列上做串匹配。我们首先要了解一个小套路:一棵子树上的点在DFS序列(即先序遍历)中是连续的。了解了这个小套路之后,我们可以确定这个问题的方向就是:把s和t先转换成DFS序,然后看t的DFS序是否是s的DFS序的子串。这样做一定正确吗,其实不一定,假设s有两个节点,1是根,2是左孩子,而t也有两个节点,1也是根,但是2是右孩子。这样一来s和t的DFS序列相同可是t并不是s的子树。由此可见,“s的DFS序包含t的DFS序”是“t是s子树”的必要不充分条件,所以单纯这样做是不正确的。为了解决这个问题,我们引入两个空值lNull和rNull,当一个节点的左孩子或者右孩子为空时,就插入这两个空值,这样DFS序列就唯一对应一棵树。然后,在判断“s的DFS序包含t的DFS序”的时候,可以暴力匹配也可以使用KMP算法。该方法如2所示,其中搜索时用了KMP算法。这个算法的时间复杂度是O( | s | + | t | ),空间复杂度是O( | s | + | t | )。 |
python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isSubtree1(self, s: TreeNode, t: TreeNode) -> bool:
if not s:
return False
if self.helper(s, t):
return True
else:
return self.isSubtree1(s.left, t) or self.isSubtree1(s.right, t)
def helper(self, tmps, tmpt):
if not tmps and not tmpt:
return True
if not tmps or not tmpt:
return False
return tmps.val == tmpt.val and self.helper(tmps.left, tmpt.left) and self.helper(tmps.right, tmpt.right)
def isSubtree2(self, s: TreeNode, t: TreeNode) -> bool:
def _serialize(root):
if not root:
return '#'
# Split symbol ',': Solve the problem of case [12], [2]
return ',' + str(root.val) + ',' + _serialize(root.left) + ',' + _serialize(root.right)
sstr = _serialize(s)
tstr = _serialize(t)
print(sstr, tstr)
return sstr.find(tstr) != -1
C++:
class Solution1 {
public:
bool check(TreeNode *o, TreeNode *t) {
if (!o && !t) {
return true;
}
if ((o && !t) || (!o && t) || (o->val != t->val)) {
return false;
}
return check(o->left, t->left) && check(o->right, t->right);
}
bool dfs(TreeNode *o, TreeNode *t) {
if (!o) {
return false;
}
return check(o, t) || dfs(o->left, t) || dfs(o->right, t);
}
bool isSubtree(TreeNode *s, TreeNode *t) {
return dfs(s, t);
}
};
class Solution2 {
public:
vector <int> sOrder, tOrder;
int maxElement, lNull, rNull;
void getMaxElement(TreeNode *o) {
if (!o) {
return;
}
maxElement = max(maxElement, o->val);
getMaxElement(o->left);
getMaxElement(o->right);
}
void getDfsOrder(TreeNode *o, vector <int> &tar) {
if (!o) {
return;
}
tar.push_back(o->val);
if (o->left) {
getDfsOrder(o->left, tar);
} else {
tar.push_back(lNull);
}
if (o->right) {
getDfsOrder(o->right, tar);
} else {
tar.push_back(rNull);
}
}
bool kmp() {
int sLen = sOrder.size(), tLen = tOrder.size();
vector <int> fail(tOrder.size(), -1);
for (int i = 1, j = -1; i < tLen; ++i) {
while (j != -1 && tOrder[i] != tOrder[j + 1]) {
j = fail[j];
}
if (tOrder[i] == tOrder[j + 1]) {
++j;
}
fail[i] = j;
}
for (int i = 0, j = -1; i < sLen; ++i) {
while (j != -1 && sOrder[i] != tOrder[j + 1]) {
j = fail[j];
}
if (sOrder[i] == tOrder[j + 1]) {
++j;
}
if (j == tLen - 1) {
return true;
}
}
return false;
}
bool isSubtree(TreeNode* s, TreeNode* t) {
maxElement = INT_MIN;
getMaxElement(s);
getMaxElement(t);
lNull = maxElement + 1;
rNull = maxElement + 2;
getDfsOrder(s, sOrder);
getDfsOrder(t, tOrder);
return kmp();
}
};
PREVIOUSlc057.另一个树的子树
NEXTlc023.合并K个排序链表