题目链接

LeetCode

题目描述

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。

26. 树的子结构 - 图1

解题思路

若树 B 是树 A 的子结构,则子结构的根节点可能为树 A 的任意一个节点。因此,判断树 B 是否是树 A 的子结构,需完成以下两步工作:

  1. 先序遍历树 A 中的每个节点 n_A。(对应函数 isSubStructure(A, B))
  2. 判断树 A 中 以 n_A为根节点的子树 是否包含树 B 。(对应函数 recur(A, B))

26. 树的子结构 - 图2

算法流程:

名词规定:树 A 的根节点记作 节点 A ,树 B 的根节点称为 节点 B 。

recur(A, B) 函数
终止条件

  1. 当节点 B 为空:说明树 B 已匹配完成(越过叶子节点),因此返回 true ;
  2. 当节点 A 为空:说明已经越过树 A 叶子节点,即匹配失败,返回 false ;
  3. 当节点 A 和 B 的值不同:说明匹配失败,返回 false ;

返回值

  1. 判断 A 和 B 的左子节点是否相等,即 recur(A.left, B.left) ;
  2. 判断 A 和 B 的右子节点是否相等,即 recur(A.right, B.right) ;

isSubStructure(A, B) 函数

  1. 特例处理: 当 树 A 为空 或 树 B 为空 时,直接返回 false ;
  2. 返回值: 若树 B 是树 A 的子结构,则必满足以下三种情况之一,因此用或 || 连接;
    • 以 节点 A 为根节点的子树 包含树 B ,对应 recur(A, B);
    • 树 B 是 树 A 左子树 的子结构,对应 isSubStructure(A.left, B);
    • 树 B 是 树 A 右子树 的子结构,对应 isSubStructure(A.right, B);
  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12. bool isSubStructure(TreeNode* A, TreeNode* B) {
  13. // 有一个为空时,返回false
  14. if(A==NULL||B==NULL) return false;
  15. // 判断当前和左右子树是否有满足条件的
  16. return recur(A,B)||isSubStructure(A->left,B)||isSubStructure(A->right,B);
  17. }
  18. bool recur(TreeNode* A,TreeNode* B){
  19. if(B==NULL) return true;
  20. if(A==NULL) return false;
  21. if(A->val!=B->val) return false;
  22. // 查找左右子结点
  23. return recur(A->left,B->left)&&recur(A->right,B->right);
  24. }
  25. };
  • 时间复杂度 O(MN) : 其中 M,N 分别为树 A 和 树 B 的节点数量;先序遍历树 A 占用 O(M) ,每次调用 recur(A, B) 判断占用 O(N) 。
  • 空间复杂度 O(M) : 当树 A 和树 B 都退化为链表时,递归调用深度最大。当 M≤N 时,遍历树 A 与递归判断的总递归深度为 M ;当 M>N 时,最差情况为遍历至树 A 叶子节点,此时总递归深度为 M