您好,登录后才能下订单哦!
在二叉树中,最近公共祖先(Lowest Common Ancestor, LCA)是指两个节点在树中最近的共同祖先节点。寻找最近公共祖先是二叉树中的一个经典问题,广泛应用于各种算法和数据结构中。本文将详细介绍如何在Java中实现寻找二叉树的最近公共祖先,并探讨不同的解决方案及其优缺点。
给定一棵二叉树和两个节点 p
和 q
,找到这两个节点的最近公共祖先。最近公共祖先的定义是:在二叉树中,p
和 q
的最低共同祖先节点,且该节点是 p
和 q
的祖先中深度最大的一个。
考虑以下二叉树:
3
/ \
5 1
/ \ / \
6 2 0 8
/ \
7 4
5
和 1
的最近公共祖先是 3
。5
和 4
的最近公共祖先是 5
。6
和 2
的最近公共祖先是 5
。递归法是解决二叉树问题的常用方法。我们可以通过递归遍历二叉树来寻找 p
和 q
的最近公共祖先。
null
,或者当前节点就是 p
或 q
,则返回当前节点。p
和 q
。null
值,说明 p
和 q
分别位于当前节点的左右子树中,当前节点即为最近公共祖先。null
值,说明 p
和 q
都在左子树中,返回左子树的结果。null
值,说明 p
和 q
都在右子树中,返回右子树的结果。class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
return left != null ? left : right;
}
}
递归法虽然简洁,但在某些情况下可能会导致栈溢出。为了避免这种情况,我们可以使用迭代法来寻找最近公共祖先。
p
的所有祖先:从 p
开始,通过父指针映射向上遍历,记录 p
的所有祖先节点。q
的最近公共祖先:从 q
开始,通过父指针映射向上遍历,直到找到第一个在 p
的祖先集合中的节点,该节点即为最近公共祖先。import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
Map<TreeNode, TreeNode> parent = new HashMap<>();
Set<TreeNode> ancestors = new HashSet<>();
// 遍历二叉树,记录每个节点的父节点
dfs(root, parent);
// 找到 p 的所有祖先
while (p != null) {
ancestors.add(p);
p = parent.get(p);
}
// 找到 q 的最近公共祖先
while (q != null) {
if (ancestors.contains(q)) {
return q;
}
q = parent.get(q);
}
return null;
}
private void dfs(TreeNode node, Map<TreeNode, TreeNode> parent) {
if (node == null) {
return;
}
if (node.left != null) {
parent.put(node.left, node);
dfs(node.left, parent);
}
if (node.right != null) {
parent.put(node.right, node);
dfs(node.right, parent);
}
}
}
p
和 q
的祖先。p
的所有祖先。在某些情况下,我们可能不希望使用额外的空间来存储父指针。我们可以通过迭代法来寻找最近公共祖先,而不需要显式地记录父节点。
p
和 q
的路径。p
和 q
的路径中最后一个相同的节点,该节点即为最近公共祖先。import java.util.Stack;
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
Stack<TreeNode> stack = new Stack<>();
Stack<TreeNode> pathP = new Stack<>();
Stack<TreeNode> pathQ = new Stack<>();
// 遍历二叉树,记录从根节点到 p 和 q 的路径
dfs(root, p, q, stack, pathP, pathQ);
// 找到路径中最后一个相同的节点
TreeNode lca = null;
while (!pathP.isEmpty() && !pathQ.isEmpty()) {
TreeNode nodeP = pathP.pop();
TreeNode nodeQ = pathQ.pop();
if (nodeP == nodeQ) {
lca = nodeP;
} else {
break;
}
}
return lca;
}
private void dfs(TreeNode node, TreeNode p, TreeNode q, Stack<TreeNode> stack, Stack<TreeNode> pathP, Stack<TreeNode> pathQ) {
if (node == null) {
return;
}
stack.push(node);
if (node == p) {
pathP.addAll(stack);
}
if (node == q) {
pathQ.addAll(stack);
}
dfs(node.left, p, q, stack, pathP, pathQ);
dfs(node.right, p, q, stack, pathP, pathQ);
stack.pop();
}
}
p
和 q
的路径。在本文中,我们介绍了三种在Java中寻找二叉树最近公共祖先的方法:递归法、迭代法(使用父指针)和迭代法(不使用父指针)。每种方法都有其优缺点,适用于不同的场景。
在实际应用中,可以根据具体需求选择合适的方法。如果二叉树的深度不大,递归法是一个简单而有效的选择。如果二叉树的深度较大,或者需要避免栈溢出问题,可以考虑使用迭代法。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。