本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
一、题目描述
在二叉树中,根节点位于深度0处,每个深度为k的节点的子节点位于深度k+1处。
如果二叉树的两个节点深度相同,但 **父节点不同 **,则它们是一对堂兄弟节点。
我们给出了具有唯一值的二叉树的根节点root,以及树中两个不同节点的值x和y 。
只有与值x和y对应的节点是堂兄弟节点时,才返回true 。否则,返回false。
示例 1:
输入:root = [1,2,3,4], x = 4, y = 3 输出:false
示例 2:
输入:root = [1,2,3,null,4,null,5], x = 5, y = 4 输出:true
示例 3:
输入:root = [1,2,3,null,4], x = 2, y = 3 输出:false
提示:
- 二叉树的节点数介于
2到100之间。 - 每个节点的值都是唯一的、范围为
1到100的整数。
二、分析
两个节点是堂兄弟节点的条件:两个节点在同一层但是它们的父节点不同,所以只要遍历这棵树,遍历过程中维护每个节点的父节点和深度,比较这两个节点的深度和父节点即可。所以问题转化为遍历一棵二叉树,遍历二叉树的方法很多,前序遍历,中序遍历,后序遍历,这些属于DFS(深度优先遍历),当然也可以用BFS(广度优先遍历),其实就是层级遍历
先看一下二叉树前序遍历递归方式,这段代码应该要不假思索地写出来。我们在这个基础上改造就可以了
public void preOrderTraverse(TreeNode root) {
if (root != null) {
System.out.print(root.val + "->");
preOrderTraverse(root.left);
preOrderTraverse(root.right);
}
}
要点就是在preOrderTraverse方法中增加两个参数parent和depth,用来表示当前遍历节点的父节点和当前节点的深度,preOrderTraverse每次调用时都会遍历root.left或者root.right,遍历的是下一层所以父节点是root,深度depth直接加1就OK了
class Solution {
int x;
int y;
int xParent;
int xDepth;
int yParent;
int yDepth;
public boolean isCousins(TreeNode root, int x, int y) {
this.x = x;
this.y = y;
preOrderTraverse(root, root, 1);
return xParent != yParent && xDepth == yDepth;
}
public void preOrderTraverse(TreeNode root, TreeNode parent, int depth) {
if (root != null) {
if (root.val == x) {
this.xParent = parent.val;
this.xDepth = depth;
}
if (root.val == y) {
this.yParent = parent.val;
this.yDepth = depth;
}
// System.out.print(root.val + "(" + parent.val + depth + ")" + "->");
preOrderTraverse(root.left, root, depth + 1);
preOrderTraverse(root.right, root, depth + 1);
}
}
}
三、总结
时间复杂度为O(n),n就是这棵树的节点个数,遍历一棵树就是遍历这n个节点。上述代码还有优化的地方,在遍历过程中,应该是找到了就推出循环,而不是要把整棵树遍历完。