二叉树最近公共祖先(LCA)

问题:

给定一个二叉树,找到两个节点NA, NB的最近公共祖先(LCA)。

比如对于下图,4 和 7 的 LCA 是6, 1和13的LCA 是 8。


我们这里先考虑一般的二叉树(BT),然后再考虑这个二叉树是二叉搜索树(BST)的情况。

查找两个node的最早的公共祖先,分三种情况:
1. 如果两个node在root的两边,那么最早的公共祖先就是root。
2. 如果两个node在root的左边,那么把root.leftChild作为root,再递归。
3. 如果两个node在root的右边,那么把root.rightChild作为root,再递归。
那么我们如何知道能否通过原始节点到达某一个节点呢?这里我们需要定义一个递归函数covers (Node root, Node node),让root的左右子节点不断的调用这个函数,如果某一个子节点就是要找到的节点,那么返回true,否则返回false. 具体代码如下:
  1. /* 
  2.      * check whether the node n is in the tree 
  3.      */  
  4.     private static boolean covers(Node rootNode, Node n) {  
  5.         if(rootNode == nullreturn false;  
  6.         if(rootNode == n) return true;  
  7.         return covers(rootNode.leftChild, n) || covers(rootNode.rightChild, n);  
  8.     }  
有个covers这个函数,我们要实现前面三种不同的情况,那就简单了。代码如下:
  1. /* 
  2.      * get the first common ancestor of node p and node q 
  3.      */  
  4.     public static Node commonAncestor(Node rootNode, Node p, Node q) {  
  5.         // case 2  
  6.         if (covers(rootNode.leftChild, p) && covers(rootNode.leftChild, q))  
  7.             return commonAncestor(rootNode.leftChild, p, q);  
  8.         //case 3  
  9.         if (covers(rootNode.rightChild, p) && covers(rootNode.rightChild, q))  
  10.             return commonAncestor(rootNode.rightChild, p, q);  
  11.         //case 1  
  12.         return rootNode;  
  13.     }  

如果这个二叉树是BST,那么我们可以利用BST的特点,把根节点的值与两个节点的值进行比较,如果两个节点的值都比节点的值小,那么一定在节点的左边,所以我们把节点的左子节点作为起始点,然后递归。如果两个节点的值都比祖先节点的值大,那么一定在节点的右边,所以我们把节点的右子节点作为起始点,然后递归,如果上面两张情况都不是,那么很明显,这个节点就是LCA. 代码如下:
  1. public Node LCA(Node root, Node p, Node q) {  
  2.   if (root == null || p == null || q == null ) return NULL;   
  3.   if (max(p.data, q.data) < root.data)  
  4.     return LCA(root.left, p, q);  
  5.   else if (min(p.data, q.data) > root.data)  
  6.     return LCA(root.right, p, q);  
  7.   else  
  8.     return root;  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值