子结构判断
LCR 143. 子结构判断
参考题解
题前知识
1)子结构
首先我们先了解一下子结构:
- 原题信息:判断
tree2是否以tree1的某个节点为根的子树具有 相同的结构和节点值 。 - 子结构也就是
B树是否含于A树左子树或者右子树之中,并且具有相同的结构和节点值,或者是否以A树的根节点作为子树
2)先序遍历
该题使用到了先序遍历,先序遍历相关代码
先序遍历规则:根左右
public List<Integer> preorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<>();dfs(res, root);return res;
}
private void dfs(List<Integer> res, TreeNode root){if(root == null){return;}res.add(root.val);dfs(res, root.left);dfs(res, root.right);}
正题
我们可以使用先序遍历树A的每个节点,然后我们判断A树是否包含B树
由于我们判断A树是否包含B树是从根节点开始匹配的,所以先序遍历的更合适本题
判断A树是否包含B树
终止条件
B为空,说明B已经匹配完成,返回true;A为空,匹配失败,B树已经越过了A的叶子结点,超出范围了,返回false;A的节点值和B的节点值不一样,返回false
返回条件
- 判断
A的左节点是否和B的左节点相等 –>recur(A.left, B.left) - 判断
A的右节点是否和B的右节点相等 –>recur(A.right, B.right)
public boolean recur(TreeNode A, TreeNode B) {if(B == null) return true;if(A == null || A.val != B.val) return false;return recur(A.left, B.left) && recur(A.right, B.right);
}
isSubStructure(A, B)函数
边界条件
A树或者B树为null,返回false
三种情况
- 以
A的根节点为子树包含B - 以
A的左子树为子树包含B - 以
A的右子树为子树包含B
以上情况只要符合一种就返回true
最终代码:
通过recur(A, B)找到B的根节点和B的子节点是否和A的匹配
public boolean isSubStructure(TreeNode A, TreeNode B) {return (A != null && B != null) && (recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B));
}public boolean recur(TreeNode A, TreeNode B) {if(B == null) return true;if(A == null || A.val != B.val) return false;return recur(A.left, B.left) && recur(A.right, B.right);
}
题后解析
关于题中用到的先序遍历思想
1、isSubStructure(A, B)中的先序遍历
对于树A的某个节点:
- 先访问根节点:执行
recur(A, B)检查当前节点是否能作为匹配的起点 - 再遍历左子树:如果根节点不匹配,递归调用
isSubStructure(A.left, B) - 最后遍历右子树:如果左子树也没有找到,递归调用
isSubStructure(A.right, B)
2、recur 方法中的先序遍历
- 先比较当前根节点的值 (
A.val != B.val) - 再递归比较左子树 (
recur(A.left, B.left)) - 最后递归比较右子树 (
recur(A.right, B.right))
