Leetcode236.二叉树的最近公共祖先 Lowest Common Ancestor of a Binary Tree(Java)

本文介绍了如何使用Java通过后续遍历和回溯法解决LeetCode题目236,探讨了递归函数的逻辑,包括判断节点、路径查找和最近公共祖先的确定。算法的时间复杂度为O(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Leetcode236.二叉树的最近公共祖先 Lowest Common Ancestor of a Binary Tree(Java)

##Tree##

二叉树的最近公共祖先

后续遍历就是天然的回溯法

采用后续遍历所有的结点,主要采用回溯的思想

  • 递归函数的作用判断是否能找到结点pq,但由于还要寻找最近的公共祖先,因此需要返回TreeNode
  • 递归出口设定为找到了pq,或者已经遍历完一条路径时,返回此时遍历的结点root
  • 左子树不空时,递归遍历左子树,返回结果为left,右子树不空时,递归遍历右子树,返回结果为right
  • 对于返回的leftright
    • leftright都为空,即要找的两结点pq都不在正在遍历结点root为根的树上,返回root
    • leftright都不为空,即要找的两结点pq分别分布在正在遍历结点的root的左子树和右子树上,此时root就是最小公共祖先,返回root
    • leftright中只有一个非空,另一个为空值,有两种情况,可能pq两个结点都分布在返回非空的一侧子树上,也可能pq只有一个结点在非空的一侧子树上,两种情况都返回leftright中的非空值

时间复杂度: O(n)

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;
        if (left != null) return left;
        if (right != null) return right;
        return null;
    }
}

可以将问题拆分为在二叉树中找根节点到结点p的路径,找根节点到节点q的路径

找到两条路径后,再在其中找出最早的公共结点,参考Leetcode160,这里不再是链表,而是动态数组

时间复杂度: O(n)

class Solution {
    Stack<TreeNode> sta = new Stack<>();
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        ArrayList<TreeNode> arr1 = new ArrayList<TreeNode>();
        dfs(root, p, arr1);
        ArrayList<TreeNode> arr2 = new ArrayList<TreeNode>();
        dfs(root, q, arr2);
        
        for (int i = arr1.size() - 1, j = arr2.size() - 1; i > 0 && j > 0; i--, j--) {
            if (arr1.get(i).val == arr2.get(j).val && arr1.get(i - 1).val != arr2.get(j - 1).val) {
                return arr1.get(i);
            } 
        }
        return arr1.size() > arr2.size() ? arr2.get(0) : arr1.get(0);
    }
    
    public boolean dfs(TreeNode root, TreeNode target, ArrayList<TreeNode> array) {
        if (root == null) return false;
        if (root.val == target.val) {
            array.add(root);
            return true;
        }
        if (dfs(root.left, target, array) || dfs(root.right, target, array)) {
            array.add(root);
            return true;
        }
        return false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值