leetcode
leetcode 1501 ~ 1550
二叉树的最近公共祖先 III

二叉树的最近公共祖先 III

难度:

标签:

题目描述

代码结果

运行时间: 33 ms, 内存: 19.1 MB


/**
 * 思路:
 * 1. 从根节点开始,同时递归查找两个目标节点p和q。
 * 2. 如果找到目标节点或遍历到叶节点,则返回当前节点。
 * 3. 如果左子树和右子树都能找到目标节点,则当前节点即为最近公共祖先。
 * 4. 如果只有一边找到,则返回找到的那边。
 *
 * Definition for a binary tree node.
 * public class Node {
 *     public int val;
 *     public Node left;
 *     public Node right;
 *     public Node parent;
 *     public Node(int x) { val = x; }
 * }
 */
import java.util.HashSet;
import java.util.Set;

public class Solution {
    public Node lowestCommonAncestor(Node p, Node q) {
        Set<Node> ancestors = new HashSet<>();
        // 从节点p开始追溯其父节点
        while (p != null) {
            ancestors.add(p);
            p = p.parent;
        }
        // 使用stream方法从节点q追溯其父节点
        return Stream.iterate(q, Objects::nonNull, node -> node.parent)
                     .filter(ancestors::contains)
                     .findFirst()
                     .orElse(null); // 找到最近公共祖先或返回null
    }
}

解释

方法:

此题解采用了父指针迭代的方法来查找二叉树的最近公共祖先。首先,定义一个辅助函数 findParent 用来收集从给定节点到根节点的路径。对于每个节点 p 和 q,使用 findParent 函数生成两个列表 p_parents 和 q_parents,分别存储从根节点到 p 和 q 的路径。然后,将两个列表逆序,从根节点开始比较,找出最后一个相同的节点,即为最近公共祖先。

时间复杂度:

O(h)

空间复杂度:

O(h)

代码细节讲解

🦆
题解中提到了使用父指针迭代方法,这种方法是否要求每个节点必须包含一个有效的父指针?如果父指针为null,该如何处理?
是的,使用父指针迭代方法要求每个节点都必须有一个有效的父指针指向其父节点。如果节点的父指针为null,这通常意味着该节点是根节点。在实现中,当遇到父指针为null的情况时,应当停止向上追溯,因为已经到达了树的根部。
🦆
在比较节点值时,是否有可能因为不同节点具有相同的值而导致错误地判断它们为公共祖先?如果是,应该如何避免这种情况?
在此题解中,应该直接比较节点对象而非节点的值,以避免由于节点值重复导致错误判断的情况。比较节点对象能确保即使两个不同的节点具有相同的值,也不会被错误地认为是相同的节点。因此,应该使用 `p_parents[i] == q_parents[i]` 而非 `p_parents[i].val == q_parents[i].val` 来进行比较。
🦆
题解中提到返回最近公共祖先是通过访问p_parents[i - 1],但如果p和q是相同的节点,这种索引方式是否会导致数组越界错误?应该如何处理?
如果p和q是相同的节点,那么在比较过程中,i将增加到1(因为至少有一个相同的节点,即它们自身),所以访问p_parents[i - 1]时i - 1为0,这是有效的索引,不会导致数组越界。因此,该实现在p和q为相同节点的情况下是安全的。
🦆
此算法是否能够有效处理当一个给定节点是另一个给定节点的祖先的情形,而无需遍历整个树?
是的,此算法能有效处理这种情况。因为算法是通过追踪两个节点到根节点的路径来确定最近公共祖先的。如果一个节点是另一个节点的直接祖先,那么在比较两个路径时,这个祖先节点将是两个列表中首个不同的节点之前的最后一个相同节点。因此,算法只需关注两个节点到根的路径,而不需要遍历整棵树。

相关问题