Java怎么找二叉树的最近公共祖先

发布时间:2022-04-14 10:34:52 作者:zzz
来源:亿速云 阅读:202

Java怎么找二叉树的最近公共祖先

在二叉树中,最近公共祖先(Lowest Common Ancestor, LCA)是指两个节点在树中最近的共同祖先节点。寻找最近公共祖先是二叉树中的一个经典问题,广泛应用于各种算法和数据结构中。本文将详细介绍如何在Java中实现寻找二叉树的最近公共祖先,并探讨不同的解决方案及其优缺点。

1. 问题定义

给定一棵二叉树和两个节点 pq,找到这两个节点的最近公共祖先。最近公共祖先的定义是:在二叉树中,pq 的最低共同祖先节点,且该节点是 pq 的祖先中深度最大的一个。

示例

考虑以下二叉树:

        3
       / \
      5   1
     / \ / \
    6  2 0  8
      / \
     7   4

2. 解决方案

2.1 递归法

递归法是解决二叉树问题的常用方法。我们可以通过递归遍历二叉树来寻找 pq 的最近公共祖先。

算法步骤

  1. 递归终止条件:如果当前节点为 null,或者当前节点就是 pq,则返回当前节点。
  2. 递归左右子树:递归地在左子树和右子树中寻找 pq
  3. 判断结果
    • 如果左子树和右子树都返回非 null 值,说明 pq 分别位于当前节点的左右子树中,当前节点即为最近公共祖先。
    • 如果只有左子树返回非 null 值,说明 pq 都在左子树中,返回左子树的结果。
    • 如果只有右子树返回非 null 值,说明 pq 都在右子树中,返回右子树的结果。

代码实现

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;
    }
}

复杂度分析

2.2 迭代法(使用父指针)

递归法虽然简洁,但在某些情况下可能会导致栈溢出。为了避免这种情况,我们可以使用迭代法来寻找最近公共祖先。

算法步骤

  1. 遍历二叉树:使用深度优先搜索(DFS)或广度优先搜索(BFS)遍历二叉树,记录每个节点的父节点。
  2. 构建父指针映射:通过遍历,我们可以构建一个从节点到其父节点的映射。
  3. 找到 p 的所有祖先:从 p 开始,通过父指针映射向上遍历,记录 p 的所有祖先节点。
  4. 找到 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);
        }
    }
}

复杂度分析

2.3 迭代法(不使用父指针)

在某些情况下,我们可能不希望使用额外的空间来存储父指针。我们可以通过迭代法来寻找最近公共祖先,而不需要显式地记录父节点。

算法步骤

  1. 使用栈进行遍历:使用栈来模拟递归过程,遍历二叉树。
  2. 记录路径:在遍历过程中,记录从根节点到 pq 的路径。
  3. 比较路径:找到 pq 的路径中最后一个相同的节点,该节点即为最近公共祖先。

代码实现

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();
    }
}

复杂度分析

3. 总结

在本文中,我们介绍了三种在Java中寻找二叉树最近公共祖先的方法:递归法、迭代法(使用父指针)和迭代法(不使用父指针)。每种方法都有其优缺点,适用于不同的场景。

在实际应用中,可以根据具体需求选择合适的方法。如果二叉树的深度不大,递归法是一个简单而有效的选择。如果二叉树的深度较大,或者需要避免栈溢出问题,可以考虑使用迭代法。

推荐阅读:
  1. 二叉树找到最近公共祖先示例
  2. java二叉树找到最近公共祖先的方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:SpringBoot怎么实现WebSocket即时通讯

下一篇:Java怎么验证时间格式是否正确

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》