算法 | 二叉树的堂兄弟节点
前言
要想判断两个节点 x 和 y 是否为堂兄弟节点,我们就需要求出这两个节点分别的「深度」以及「父节点」。
因此,我们可以从根节点开始,对树进行一次遍历,在遍历的过程中维护「深度」以及「父节点」这两个信息。当我们遍历到 x 或 y 节点时,就将信息记录下来;当这两个节点都遍历完成了以后,我们就可以退出遍历的过程,判断它们是否为堂兄弟节点了。
常见的遍历方法有两种:深度优先搜索和广度优先搜索。
方法一:深度优先搜索
思路与算法
我们只需要在深度优先搜索的递归函数中增加表示「深度」以及「父节点」的两个参数即可。
代码
class Solution {// x 的信息int x;TreeNode xParent;int xDepth;boolean xFound = false;// y 的信息int y;TreeNode yParent;int yDepth;boolean yFound = false;public boolean isCousins(TreeNode root, int x, int y) {this.x = x;this.y = y;dfs(root, 0, null);return xDepth == yDepth && xParent != yParent;}public void dfs(TreeNode node, int depth, TreeNode parent) {if (node == null) {return;}if (node.val == x) {xParent = parent;xDepth = depth;xFound = true;} else if (node.val == y) {yParent = parent;yDepth = depth;yFound = true;}// 如果两个节点都找到了,就可以提前退出遍历// 即使不提前退出,对最坏情况下的时间复杂度也不会有影响if (xFound && yFound) {return;}dfs(node.left, depth + 1, node);if (xFound && yFound) {return;}dfs(node.right, depth + 1, node);}}
复杂度分析
时间复杂度:O(n)O(n),其中 n 是树中的节点个数。在最坏情况下,我们需要遍历整棵树,时间复杂度为 O(n)O(n)。
空间复杂度:O(n)O(n),即为深度优先搜索的过程中需要使用的栈空间。在最坏情况下,树呈现链状结构,递归的深度为 O(n)O(n)。
方法二:广度优先搜索
思路与算法
在广度优先搜索的过程中,每当我们从队首取出一个节点,它就会作为「父节点」,将最多两个子节点放入队尾。因此,除了节点以外,我们只需要在队列中额外存储「深度」的信息即可。
代码
class Solution {// x 的信息int x;TreeNode xParent;int xDepth;boolean xFound = false;// y 的信息int y;TreeNode yParent;int yDepth;boolean yFound = false;public boolean isCousins(TreeNode root, int x, int y) {this.x = x;this.y = y;Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();Queue<Integer> depthQueue = new LinkedList<Integer>();nodeQueue.offer(root);depthQueue.offer(0);update(root, null, 0);while (!nodeQueue.isEmpty()) {TreeNode node = nodeQueue.poll();int depth = depthQueue.poll();if (node.left != null) {nodeQueue.offer(node.left);depthQueue.offer(depth + 1);update(node.left, node, depth + 1);}if (node.right != null) {nodeQueue.offer(node.right);depthQueue.offer(depth + 1);update(node.right, node, depth + 1);}if (xFound && yFound) {break;}}return xDepth == yDepth && xParent != yParent;}// 用来判断是否遍历到 x 或 y 的辅助函数public void update(TreeNode node, TreeNode parent, int depth) {if (node.val == x) {xParent = parent;xDepth = depth;xFound = true;} else if (node.val == y) {yParent = parent;yDepth = depth;yFound = true;}}}
复杂度分析
时间复杂度:O(n)O(n),其中 n 是树中的节点个数。在最坏情况下,我们需要遍历整棵树,时间复杂度为 O(n)O(n)。
空间复杂度:O(n)O(n),即为广度优先搜索的过程中需要使用的队列空间。
