转自:Pavel's Blog

Now let's say we want to find the LCA for nodes 4 and 9, we will need to traverse the whole tree to compare each node so that we can locate the nodes. Now considering that we start the traversal with the left branch (pre-order traversal) - we have the worst case here with O(n) running time.
Traversing the tree we compare the current node with both of the nodes and if one of them match, it means that one is the LCA on the respective branch. Let's say after traversing the above tree in pre-order  the first node that matches our nodes is 9 (2, 7, 2, 6, 5, 11, 5, 9). So the first obvious thought is that the 4 must be a child of 9, since we're already on the right child of node 5 and the pre-order traversal looks at the node first, then the left child and lastly the right child. Then we note node 9 as the LCA and we don't have to look further anymore.
 
Let's use another case, say we're looking for the LCA of 7 and 9. The first node in our pre-order traversal (2, 7, 2, 6, 5, 11, 5, 9, 4) is 7. Now here we can say that the LCA for the left branch is 7 because again, if the second node is in the same branch, independently of where and how deep it will be in this branch, the LCA will still be 7; thus we don't have to look in this branch anymore. But we still did not look at the right branch, so we keep traversing in a pre-order manner, but now omitting the other nodes: 2, 7, 5, 9. Now we can say that the LCA for that branch is 9. We can also affirm that the LCA for the branch with the root in node 5 is also 9. And in the end we have our nodes both in separate branches, which means that the LCA is the root of those branches - node 2.
 
The algorithm looks as a modified version of a pre-order tree traversal :

 public static Node lowestCommonAncestor(Node root, Node a, Node b) {
if (root == null) {
return null;
} if (root.equals(a) || root.equals(b)) {
// if at least one matched, no need to continue
// this is the LCA for this root
return root;
} Node l = lowestCommonAncestor(root.left, a, b);
Node r = lowestCommonAncestor(root.right, a, b); if (l != null && r != null) {
return root; // nodes are each on a seaparate branch
} // either one node is on one branch,
// or none was found in any of the branches
return l != null ? l : r;
}

For the node used we will use the following class:

 public class Node {
public int data;
public Node right;
public Node left; public Node(int data) {
this.data = data;
}
}

这个问题再follow up一下,就是要找到shortest path in a binary tree between two nodes

 public class Solution {
public static List<Node> shortestPath(Node root, Node a, Node b) {
ArrayList<Node> path1 = new ArrayList<Node>();
ArrayList<Node> path2 = new ArrayList<Node>();
Node LCA = lowestCommonAncestor(root, a, b);
helper(LCA.left, a, b, path1, new ArrayList<Node>());
helper(LCA.right, a, b, path2, new ArrayList<Node>());
Collections.reverse(path1);
path1.add(LCA);
path1.addAll(new ArrayList<Node>(path2));
return path1;
} public void helper(Node root, Node a, Node b, ArrayList<Node> outpath, ArrayList<Node> temp) {
if (root == null) return;
temp.add(root);
if (root == a || root == b) {
outpath = new ArrayList<Node>(temp);
return;
}
helper(root.left, a, b, outpath, temp);
helper(root.right, a, b, outpath, temp);
temp.remove(temp.size()-1);
}
}

别人的Stack做法,未深究 他说First stack is not really needed, a simple list would do - I just like symmetry.

 public static <V> void shortestpath(
Node<V> root, Node<V> a, Node<V> b,
Stack<Node<V>> outputPath) {
if (root == null) {
return;
}
if (root.data.equals(a.data) || root.data.equals(b.data)) {
outputPath.push(root);
return;
} shortestpath(root.left, a, b, outputPath);
shortestpath(root.right, a, b, outputPath); outputPath.push(root);
} public static List<Node> shortestPath(Node root, Node a, Node b) {
Stack<Node> path1 = new Stack<>();
Stack<Node> path2 = new Stack<>(); Node lca = lowestCommonAncestor(root, a, b); // This is to handle the case where one of the nodes IS the LCA
Node r = lca.equals(a) ? a : (lca.equals(b) ? b : lca); shortestpath(r.left, a, b, path1);
shortestpath(r.right, a, b, path2); path1.push(r);
// invert the second path
while (!path2.isEmpty()) {
path1.push(path2.pop());
}
return path1;
}

Summary: Lowest Common Ancestor in a Binary Tree & Shortest Path In a Binary Tree的更多相关文章

  1. Range Minimum Query and Lowest Common Ancestor

    作者:danielp 出处:http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAnc ...

  2. A1143. Lowest Common Ancestor

    The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...

  3. PAT A1143 Lowest Common Ancestor (30 分)——二叉搜索树,lca

    The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...

  4. 1143 Lowest Common Ancestor

    The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...

  5. PAT 甲级 1143 Lowest Common Ancestor

    https://pintia.cn/problem-sets/994805342720868352/problems/994805343727501312 The lowest common ance ...

  6. PAT 1143 Lowest Common Ancestor[难][BST性质]

    1143 Lowest Common Ancestor(30 分) The lowest common ancestor (LCA) of two nodes U and V in a tree is ...

  7. [PAT] 1143 Lowest Common Ancestor(30 分)

    1143 Lowest Common Ancestor(30 分)The lowest common ancestor (LCA) of two nodes U and V in a tree is ...

  8. 1143. Lowest Common Ancestor (30)

    The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...

  9. PAT 1143 Lowest Common Ancestor

    The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...

随机推荐

  1. 第二步 使用Cordova 3.0(及以上版本) 创建安卓项目(2014-6-25)

    参考资料: http://www.cnblogs.com/numtech/p/3233469.html http://blog.sina.com.cn/s/blog_9e245c690101jurr. ...

  2. shell 进制转换

    包括: i.任意进制转化为十进制((num=base#number)) [base和number必须一致,是同一种进制] ii.十进制转化为任意进制`echo "obase=进制;值&quo ...

  3. 上传控件---淘宝kissy uploader+瀑布流显示

    介绍Uploader : Uploader 是由阿里集团前端工程师们发起创建的一个开源 JS 框架.它具备模块化.高扩展性.组件齐全,接口一致.自主开发.适合多种应用场景等特性. Uploader是非 ...

  4. Unix/Linux 查看文件大小

    ls -l help.html-rw-r--r--  1 william  wheel  40960 Jul 18 00:59 development.sqlite3 40960 就是文件的大小. d ...

  5. Egret的屏幕适配模式图示

    1 ShowAll 过长时,上边有边框 过短时,左右有边框 2 noScale 不会进行任何缩放 3 noBorder 过长时,裁减左右 过短时,裁减上下 4 fixedWidth 过长时,下方有边框 ...

  6. Yet another way to manage your NHibernate ISessionFactory

    So here is my current UnitOfWork implementation.  This one makes use of the somewhat new current_ses ...

  7. yii---模型的创建

    在 model/ 路径新建 Test.php 模型 我们类的名称一定要与数据表的名称相同. 继承 yii\db\ActiveRecord 类: 在模型类中 声明 tableName() 指定表名 // ...

  8. opengl学习笔记(二):使用OpenCV来创建OpenGL窗口

    通常的增强现实应用需要支持OpenGL的OpenCV来对真实场景进行渲染.从2.4.2版本开始,OpenCV在可视化窗口中支持OpenGL.这意味着在OpenCV中可轻松渲染任何3D内容. 若要在Op ...

  9. Mapreduce 原理及程序分析

    1.MapReduce(Map+Reduce) 提出一个问题: 目标:你想数出一摞牌中有多少张黑桃. 直观方式:一张一张检查并且数出有多少张是黑桃数目 MapReduce方法则是: 给在座的所有玩家中 ...

  10. POJ 2398 - Toy Storage - [计算几何基础题][同POJ2318]

    题目链接:http://poj.org/problem?id=2398 Time Limit: 1000MS Memory Limit: 65536K Description Mom and dad ...