一、题目描述
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)。B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:
3
/ \
4 5
/ \
1 2
给定的树 B:
4
/
1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例1:
输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1]
输出:true
限制:
0<=节点个数<=10000
二、思路分析
注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献
思路
若树
B
是树A
的子结构,则子结构的根节点可能为树A
的任意一个节点。因此,判断树B
是否是树A
的子结构,需完成以下两步工作:
①先序遍历树A
中的每个节点 n A n_A nA(对应函数isSubStructure(A, B)
)
②判断树A
中以 n A n_A nA为根节点的子树是否包含树B
(对应函数recur(A, B)
)
算法流程:
①对于isSubStructure(A->left, B)函数
特例处理:
判断A、B是否为空,有一者为空,返回false
,只有两者都不为空才能进入下一步。
返回值:
----A的当前节点与B:recur(A, B)
----A的左子树与B:isSubStructure(A->left, B)
----A的右子树与B:isSubStructure(A->right, B)
三种情况有其一满足即可,用或(||)连接(上面的操作实质上也是在对A进行先序遍历)。
②对于recur(A, B)函数
终止条件:
----如果B为空,说明树B已匹配完成(越过叶子节点),返回true
----如果A为空,说明已经越过树A 叶子节点,即匹配失败,返回false
----如果A和B的值不相等,说明不匹配,返回false
返回值:
----返回recur(A->left,B->left)&&recur(A->left,B->left)
复杂度分析:
时间复杂度 O ( M N ) \rm{O(MN)} O(MN): 其中M
、N
分别为树A
和树B
的节点数量。先序遍历树A
占用O(M)
,每次调用recur(A, B)判断占用O(N)
。
空间复杂度 O ( M ) \rm{O(M)} O(M): 当树A
和树B
都退化为链表时,递归调用深度最大。当 M ≤ N {\rm{M}} \le {\rm{N}} M≤N 时,遍历树A
与递归判断的总递归深度为M
。当 M > N {\rm{M > N}} M>N时,最差情况为遍历至树A
叶子节点,此时总递归深度为M
。
三、整体代码
整体代码如下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool recur(struct TreeNode* A, struct TreeNode* B)
{
if(!B){
return true;
}
if(!A || A->val != B->val){
return false;
}
return recur(A->left, B->left) && recur(A->right, B->right);
}
bool isSubStructure(struct TreeNode* A, struct TreeNode* B){
if(!A || !B)
{
return false;
}
return recur(A, B) || isSubStructure(A->left, B) || isSubStructure(A->right, B);
}
运行,测试通过