一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 2 天,点击查看活动详情。
题目链接
题目描述
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
测试用例
示例 1:
输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true
限制
- root 树上的节点数量范围是 [1, 2000]
- subRoot 树上的节点数量范围是 [1, 1000]
题目分析
题目中对相同的判定为,具备同样的节点层次,以及对应位置的节点的值相等
即我们需要在对 root 进行遍历的时候,需要检查每一个节点的值,是否与 subRoot 这棵树的根节点的值相等。
值不等时,继续遍历 root 的子节点
值相等时,定义 root 此时遍历的节点为 n1,我们开始对 n1, subRoot 两棵树同步遍历以及节点的值的比对,当他们的节点的层次不一致或者值不一致时,返回 false 表示此次比对 subRoot 不是 root 的子树;若当前位置的节点的值符合要求时,继续对比他们的左右子节点。考虑到这个比对操作需要全部满足才能返回 true,可以使用 && 进行短接。
比较校验的函数如下:
function check(n1, n2) {
if (n1 == null && n2 == null) return true;
if (n1 == null || n2 == null || n1.val != n2.val) return false;
return check(n1.left, n2.left) && check(n1.right, n2.right);
}
代码实现
分析完成后,我们需要定义一个对 root 遍历的函数,以及比较两颗树是否相同的函数
在遍历和比较的时候,穿插一个 flag 标记 root 中是否存在目标子树
最后的成品代码如下:
var isSubtree = function(root, subRoot) {
let flag = false;
trave(root);
return flag;
function trave(node) {
if (node == null || flag == true) return;
if (node.val == subRoot.val) {
flag = check(node, subRoot);
}
trave(node.left);
trave(node.right);
}
function check(n1, n2) {
if (n1 == null && n2 == null) return true;
if (n1 == null || n2 == null) return false;
if (n1.val == n2.val) {
return check(n1.left, n2.left) && check(n1.right, n2.right);
} else {
return false;
}
}
};