文章目录
- 题目
- 深搜
- 深搜代码
- 广搜
- 广搜代码
题目
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:
给定的树 B:
返回 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相等的节点nA
- 再判断以nA为根节点的树是否和B树相吻合
算法流程:
函数 bool dfs(TreeNode* A, TreeNode* B);
:
1. 终止条件:
- 当节点 B 为空:说明树 B 已匹配完成,因此返回
true
; - 当节点 A 为空但节点 B 不为空:说明已经越过树 A 叶子节点,即匹配失败,返回 false ;
- 当节点 A 和 B 的值不同:说明匹配失败,返回 false ;
2. 返回值:
- 判断 A 和 B 的左子节点是否相等,即 dfs(A->left, B->left) ;
- 判断 A 和 B 的右子节点是否相等,即 dfs(A->right, B->right) ;
函数 isSubStructure(TreeNode* A, TreeNode* B)
:
1. 特例处理: 当 树 A 为空
或 树 B 为空
时,直接返回 false
;
2. 返回值: 当 B 树是 A 的子树时,其必须满足以下三个条件之一:
- 以
A为根节点
的树包含 B 树 - 以
A的左子树为根节点
的树包含 B 树 - 以
A的右子树为根节点
的树包含 B 树
上面 2. 3.
的实质就是在对树 A 做先序遍历。
复杂度分析:
- 时间复杂度 O(MN) : 其中 M,N 分别为树 A 和 树 B 的节点数量;先序遍历树 A 占用 O(M) ,每次调用 dfs(A, B) 判断占用 O(N) 。
- 空间复杂度 O(M) : 当树 A 和树 B 都退化为链表时,递归调用深度最大。当 M≤N 时,遍历树 A 与递归判断的总递归深度为 M ;当 M>N 时,最差情况为遍历至树 A 叶子节点,此时总递归深度为 M。
深搜代码
class Solution {public:bool dfs(TreeNode* A, TreeNode* B){if(B==nullptr){return true;}if(A==nullptr || A->val != B->val) return false;return dfs(A->left, B->left) && dfs(A->right, B->right);}bool isSubStructure(TreeNode* A, TreeNode* B) {if(A == nullptr || B == nullptr){return false;}bool res = false;if(A->val == B->val){res = dfs(A, B);}if(res){return res;}return isSubStructure(A->left, B) || isSubStructure(A->right, B);}
};
简化版本:
class Solution {
public:bool dfs(TreeNode* A, TreeNode* B){if(B==nullptr) return true;if(A==nullptr || A->val != B->val) return false;return dfs(A->left, B->left) && dfs(A->right, B->right);}bool isSubStructure(TreeNode* A, TreeNode* B) {return (A != NULL && B != NULL) && (dfs(A, B) || isSubStructure(A->left, B) || isSubStructure(A->right, B));}
};
广搜
广搜思想中也有 判定 nA为根节点 的树与 B 树是否吻合
的部分,因此其对应的函数和深搜中起到该作用的函数是一致的,无需更改。
不一样的是 深搜用递归的的方法实现先序遍历,而 广搜用队列来实现层序遍历。
也就是说,广搜思想主要是:
- 根据层序遍历先寻找与B相等的节点nA
- 再判断以nA为根节点的树是否和B树相吻合
算法流程:
函数bool bfs(TreeNode* A, TreeNode* B);
和深搜部分一样,就不再赘述了。
函数 isSubStructure(TreeNode* A, TreeNode* B);
:
1. 特例处理: 当 树 A 为空
或 树 B 为空
时,直接返回 false
;
2. 队列实现层序遍历:
- 先将 A 入队
- 当队列不为空时:
- 将队列中的元素依次弹出,判断其与 B 是否相等。
- 相等则判断以nA为根节点的树是否吻合 B 树,吻合则直接返回。
- 不吻合则判断弹出的元素左右子树是否为空,不为空则入队。
广搜代码
/*** 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 bfs(TreeNode* A, TreeNode* B){if(B==nullptr) return true;if(A==nullptr || A->val != B->val) return false;return bfs(A->left, B->left) && bfs(A->right, B->right);}bool isSubStructure(TreeNode* A, TreeNode* B) {if(A == nullptr || B == nullptr){return false;}bool res = false;queue<TreeNode*> q;q.push(A);while(!q.empty()){size_t qs = q.size();for(size_t i = 0; i < qs; i++){auto node = q.front();q.pop();if(node->val == B->val){res = bfs(node, B);}if(res){return res;}if(node->left) q.push(node->left);if(node->right) q.push(node->right);}}return res;}
};