vlambda博客
学习文章列表

算法 | 二叉树的堂兄弟节点


前言


要想判断两个节点 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),即为广度优先搜索的过程中需要使用的队列空间。