转自: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 :

  1. public static Node lowestCommonAncestor(Node root, Node a, Node b) {
  2. if (root == null) {
  3. return null;
  4. }
  5.  
  6. if (root.equals(a) || root.equals(b)) {
  7. // if at least one matched, no need to continue
  8. // this is the LCA for this root
  9. return root;
  10. }
  11.  
  12. Node l = lowestCommonAncestor(root.left, a, b);
  13. Node r = lowestCommonAncestor(root.right, a, b);
  14.  
  15. if (l != null && r != null) {
  16. return root; // nodes are each on a seaparate branch
  17. }
  18.  
  19. // either one node is on one branch,
  20. // or none was found in any of the branches
  21. return l != null ? l : r;
  22. }

For the node used we will use the following class:

  1. public class Node {
  2. public int data;
  3. public Node right;
  4. public Node left;
  5.  
  6. public Node(int data) {
  7. this.data = data;
  8. }
  9. }

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

  1. public class Solution {
  2. public static List<Node> shortestPath(Node root, Node a, Node b) {
  3. ArrayList<Node> path1 = new ArrayList<Node>();
  4. ArrayList<Node> path2 = new ArrayList<Node>();
  5. Node LCA = lowestCommonAncestor(root, a, b);
  6. helper(LCA.left, a, b, path1, new ArrayList<Node>());
  7. helper(LCA.right, a, b, path2, new ArrayList<Node>());
  8. Collections.reverse(path1);
  9. path1.add(LCA);
  10. path1.addAll(new ArrayList<Node>(path2));
  11. return path1;
  12. }
  13.  
  14. public void helper(Node root, Node a, Node b, ArrayList<Node> outpath, ArrayList<Node> temp) {
  15. if (root == null) return;
  16. temp.add(root);
  17. if (root == a || root == b) {
  18. outpath = new ArrayList<Node>(temp);
  19. return;
  20. }
  21. helper(root.left, a, b, outpath, temp);
  22. helper(root.right, a, b, outpath, temp);
  23. temp.remove(temp.size()-1);
  24. }
  25. }

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

  1. public static <V> void shortestpath(
  2. Node<V> root, Node<V> a, Node<V> b,
  3. Stack<Node<V>> outputPath) {
  4. if (root == null) {
  5. return;
  6. }
  7. if (root.data.equals(a.data) || root.data.equals(b.data)) {
  8. outputPath.push(root);
  9. return;
  10. }
  11.  
  12. shortestpath(root.left, a, b, outputPath);
  13. shortestpath(root.right, a, b, outputPath);
  14.  
  15. outputPath.push(root);
  16. }
  17.  
  18. public static List<Node> shortestPath(Node root, Node a, Node b) {
  19. Stack<Node> path1 = new Stack<>();
  20. Stack<Node> path2 = new Stack<>();
  21.  
  22. Node lca = lowestCommonAncestor(root, a, b);
  23.  
  24. // This is to handle the case where one of the nodes IS the LCA
  25. Node r = lca.equals(a) ? a : (lca.equals(b) ? b : lca);
  26.  
  27. shortestpath(r.left, a, b, path1);
  28. shortestpath(r.right, a, b, path2);
  29.  
  30. path1.push(r);
  31. // invert the second path
  32. while (!path2.isEmpty()) {
  33. path1.push(path2.pop());
  34. }
  35. return path1;
  36. }

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. rman 中遇到 ORA-01861

    RMAN> run{ 2> sql 'alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss"'; 3> ...

  2. ELK系列六:Logstash的Filter模块

    Date过滤 input { stdin{ codec => plain } } filter { date { match => ["message", " ...

  3. docker报错“net/http: TLS handshake timeout”的解决方法

    为了永久性保留更改,您可以修改 /etc/docker/daemon.json 文件并添加上 registry-mirrors 键值. { "registry-mirrors": ...

  4. [压缩]C#下使用SevenZipSharp压缩解压文本

    using SevenZip; using System; using System.Collections.Generic; using System.IO; using System.Linq; ...

  5. CodeForce 832A Sasha and Sticks

    A. Sasha and Sticks time limit per test2 seconds memory limit per test256 megabytes inputstandard in ...

  6. opencv之Mat数据类型

    data:Mat对象中的一个指针,指向内存中存放矩阵数据的一块内存 (uchar* data) dims:Mat所代表的矩阵的维度,如 3 * 4 的矩阵为 2 维, 3 * 4 * 5 的为3维 c ...

  7. NLP常用语料集合

    常用语料资源 下面提供一些网上能下载到的中文的好语料,供研究人员学习使用.(1).中科院自动化所的中英文新闻语料库 http://www.datatang.com/data/13484中文新闻分类语料 ...

  8. MySQL ·InnoDB 文件系统之文件物理结构

    从上层的角度来看,InnoDB层的文件,除了redo日志外,基本上具有相当统一的结构,都是固定block大小,普遍使用的btree结构来管理数据.只是针对不同的block的应用场景会分配不同的页类型. ...

  9. 停机问题(英语:halting problem)是逻辑数学中可计算性理论的一个问题。通俗地说,停机问题就是判断任意一个程序是否能在有限的时间之内结束运行的问题。该问题等价于如下的判定问题:是否存在一个程序P,对于任意输入的程序w,能够判断w会在有限时间内结束或者死循环。

    htps://baike.baidu.com/item/停机问题/4131067?fr=aladdin 理发师悖论:村子里有个理发师,这个理发师有条原则是,对于村里所有人,当且仅当这个人不自己理发,理 ...

  10. 前端开发组件化设计vue,react,angular原则漫谈

    前端开发组件化设计vue,react,angular原则漫谈 https://www.toutiao.com/a6346443500179505410/?tt_from=weixin&utm_ ...