剑指 Offer 26. 树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构) B是A的子结构, 即 A中有出现和B相同的结构和节点值。
DFS+前序
思路
若B为A的子结构,则子结构的根节点可能为树A的任意一个节点,因此判断B是否为树A的子结构,需要完成如下2步工作:
**recur(A,B)**
:
- 终止条件:
- 当节点B为空,说明树B已匹配完成(越过叶子节点),true
- 当节点A为空:说明树A越过叶子节点,false
- 当节点A与B值不同:false;
- 返回值:
- 判断A和B的左子节点是否相等,即
recur(A.left,B.left);
- 判断A和B的右子节点是否相等,即
recur(A.right,B.right);
- 判断A和B的左子节点是否相等,即
isSubStructure(A, B)
函数:
- 特例处理:当树A为空或树B为空时,false;
- 返回值:若树B为树A的子结构,则必然满足如下三种情况之一,以
||
连接- 以节点A为根节点的子树包含树B,对应
recur(A,B);
- 树B是树A的左子树的子结构,对应
isSubStructure(A.left, B)
- 树B是树A的右子树的子结构,对应isSubStructure(A.right, B)
以上a.b.c实质为先序遍历
- 以节点A为根节点的子树包含树B,对应
实现(递归实现)
bool recur(TreeNode*,TreeNode*);
bool isSubStructure(TreeNode* A,TreeNode* B){
return bool(A && B)
&& (recur(A,B) || isSubStructure(A->left,B) || isSubStructure(A->right,B);
}
bool recur(TreeNode* A,TreeNode* B){
//用以判断以A为根节点的树是否包含树B
if(!B) return true;
if(!A || A->val!=B->val) return false;
return recur(A.left,B.left) && recur(A.right,B.right);
}
实现(非递归BFS实现)
bool isSubStructure(TreeNode* A,TreeNode* B){
if(!A || !B) return false;
queue<TreeNode*> qu;
qu.push(A);
while(!qu.empty()){
auto curNode=qu.front();
qu.pop();
if(bfs(curNode,B)){
return true;
}
if(curNode->left) qu.push(curNode->left);
if(curNode->right) qu.push(curNode->right);
}
return false;
}
bool bfs(TreeNode* A,TreeNode* B){
queue<TreeNode*> quA,quB;
quA.push(A);
quB.push(B);
while(!quA.empty() || !quB.empty()){
auto curA=quA.front();
auto curB=quB.front();
quA.pop();
quB.pop();
if(!curB) continue;
if(!curA || curA->val!=curB->val) return false;
quA.push(curA->left);
quA.push(curA->right);
quB.push(curB->left);
quB.push(curB->right);
}
return true;
}
复杂度分析
- 时间复杂度: ,先序遍历A树为O(M),每次A树遍历都需要调用recur(A,B),占用O(N)
- 空间复杂度:,当M<=N时,遍历树A与递归判断总深度为M;若M>N,最差情况下遍历至A的叶子节点,故总深度为M;
BFS
思路
算法
实现
复杂度分析
- 时间复杂度:
- 空间复杂度:
题目标题难度划分
星级 | 题目难度 |
---|---|
☆ | 简单 |
☆☆ | 中等 |
☆☆☆ | 困难 |
算法掌握难度程度划分
星级 | 掌握难度 |
---|---|
无 | 普通 |
❤ | 经典,易掌握 |
❤❤ | 经典,略难掌握 |
❤❤❤ | 困难 |