原文地址:Check if a binary tree is subtree of another binary tree | Set 2
已知两个二叉树,看一下第一个树是不是第二个树的子树。一个树T的子树是树S,这个树由是T中的一个节点及其它的下属节点组成的。
子树对应的是根节点的话,那就是整个树;子树对应的是任意其他节点的话叫做正常子树(proper subtree)。
例如,在下面的例子中,Tree1是Tree2的子树。
Tree1
x
/ \
a b
\
c
Tree2
z
/ \
x e
/ \ \
a b k
\
c
我们已经讨论过了 O(n2) 对这个问题的解决方法。这章讨论的是O(n)的解决方法。这个思想是基于这样一个事实,中序遍历与先序遍历/后序遍历可以唯一确定一个树。如果S的中序遍历和先序遍历分别是T的中序遍历和先序遍历的子字符串,那么S就是T的一个子树。
下面是详细步骤:
1)得到T的中序遍历与先序遍历序列,保存在两个附加的数组inT[]与preT[]中。
2)得到S的中序遍历与先序遍历序列,保存在两个附加的数组inS[]与preS[]中。
3)如果inS[]是inT[]的子数组,preS[]是preT[]的子数组,那么S就是T的一个子树。否则不是。
我们可以在上述算法中用后序遍历代替先序遍历。
我们考虑下下面的例子。
中序和先序遍历那个大一点的树。
inT[] = {a, c, x, b, z, e, k}
preT[] = {z, x, a, c, b, e, k}
中序和先序遍历那个小一点的树。
inS[] = {a, c, x, b}
preS[] = {x, a, c, b}
我们可以算出inS[]是inT[]的一个子数组,preS[]是preT[]的一个子数组。
编辑:
如果一个树在另一个树中表示,但不是子树,那么上述算法就不起作用了,考虑下面的例子。
Tree1
x
/ \
a b
/
c
Tree2
x
/ \
a b
/ \
c d
Inorder and Preorder traversals of the big tree or Tree2 are.
Inorder and Preorder traversals of small tree or Tree1 are
The Tree2 is not a subtree of Tree1, but inS[] and preS[] are subarrays of inT[] and preT[] respectively.
以上算法可以延伸到通过增加特别的字符处理这种情况,无论啥时候在中序遍历与先序遍历中遇到NULL。
下面是上述算法的代码实现。
// Java program to check if binary tree is subtree of another binary tree
class Node {
char data;
Node left, right;
Node(char item) {
data = item;
left = right = null;
}
}
class Passing {
int i;
int m = 0;
int n = 0;
}
class BinaryTree {
static Node root;
Passing p = new Passing();
String strstr(String haystack, String needle) {
if (haystack == null || needle == null) {
return null;
}
int hLength = haystack.length();
int nLength = needle.length();
if (hLength < nLength) {
return null;
}
if (nLength == 0) {
return haystack;
}
for (int i = 0; i <= hLength - nLength; i++) {
if (haystack.charAt(i) == needle.charAt(0)) {
int j = 0;
for (; j < nLength; j++) {
if (haystack.charAt(i + j) != needle.charAt(j)) {
break;
}
}
if (j == nLength) {
return haystack.substring(i);
}
}
}
return null;
}
// A utility function to store inorder traversal of tree rooted
// with root in an array arr[]. Note that i is passed as reference
void storeInorder(Node node, char arr[], Passing i) {
if (node == null) {
arr[i.i++] = '$';
return;
}
storeInorder(node.left, arr, i);
arr[i.i++] = node.data;
storeInorder(node.right, arr, i);
}
// A utility function to store preorder traversal of tree rooted
// with root in an array arr[]. Note that i is passed as reference
void storePreOrder(Node node, char arr[], Passing i) {
if (node == null) {
arr[i.i++] = '$';
return;
}
arr[i.i++] = node.data;
storePreOrder(node.left, arr, i);
storePreOrder(node.right, arr, i);
}
/* This function returns true if S is a subtree of T, otherwise false */
boolean isSubtree(Node T, Node S) {
/* base cases */
if (S == null) {
return true;
}
if (T == null) {
return false;
}
// Store Inorder traversals of T and S in inT[0..m-1]
// and inS[0..n-1] respectively
char inT[] = new char[100];
String op1 = String.valueOf(inT);
char inS[] = new char[100];
String op2 = String.valueOf(inS);
storeInorder(T, inT, p);
storeInorder(S, inS, p);
inT[p.m] = '\0';
inS[p.m] = '\0';
// If inS[] is not a substring of preS[], return false
if (strstr(op1, op2) != null) {
return false;
}
// Store Preorder traversals of T and S in inT[0..m-1]
// and inS[0..n-1] respectively
p.m = 0;
p.n = 0;
char preT[] = new char[100];
char preS[] = new char[100];
String op3 = String.valueOf(preT);
String op4 = String.valueOf(preS);
storePreOrder(T, preT, p);
storePreOrder(S, preS, p);
preT[p.m] = '\0';
preS[p.n] = '\0';
// If inS[] is not a substring of preS[], return false
// Else return true
return (strstr(op3, op4) != null);
}
//Driver program to test above functions
public static void main(String args[]) {
BinaryTree tree = new BinaryTree();
Node T = new Node('a');
T.left = new Node('b');
T.right = new Node('d');
T.left.left = new Node('c');
T.right.right = new Node('e');
Node S = new Node('a');
S.left = new Node('b');
S.right = new Node('d');
S.left.left = new Node('c');
if (tree.isSubtree(T, S)) {
System.out.println("Yes , S is a subtree of T");
} else {
System.out.println("No, S is not a subtree of T");
}
}
}
// This code is contributed by Mayank Jaiswal
输出:
No: S is NOT a subtree of T
时间复杂度:中序与先序遍历二叉树花费了O(n)的时间。函数strstr()可以用KMP字符串匹配算法实现O(n)时间的算法。
空间复杂度是:O(n)。