问题
对于普通的二叉树,如何找到两个给定节点之家的距离?距离是指连接两个节点需要的最小的边的条数。
例如下面的二叉树:

这个问题很全面的考察了二叉树相关的知识,建议大家先尝试自己解决~
分析
假设给定的节点为node1, node2,可以分为下面两种情况:
1) node1是node2的祖先节点或孩子节点,可以理解为两个节点在一条线上。 例如:Dist(2,4), Dist(6,1)
2) node1 和 node2 没有直接或间接的父子关系。 例如,Dist(4,3), 他们需要一个共同的祖先节点1 连接起来。
关于两个节点的最低公共祖先(LCA)问题,可以参考:寻找二叉树两个节点的最低公共祖先
通过观察可以总结出下面的公式, lca是两个节点的最低公共祖先节点:
Dist(n1, n2) = Dist(root, n1) + Dist(root, n2) - 2*Dist(root, lca)
这个公式已经含盖了上面的两种情况。先找出lca,再求root节点到某个节点的距离就比较简单了。
下面是Java代码实现:
17 | public class TreeNodesDistance { |
20 | public static int findLevel(Node root, int node){ |
21 | if (root == null ) return - 1 ; |
22 | if (root.key == node) return 0 ; |
24 | int level = findLevel(root.left, node); |
27 | level = findLevel(root.right, node); |
34 | public static Node findLCA(Node root, int node1, int node2){ |
35 | if (root == null ) return null ; |
38 | if (root.key == node1 || root.key == node2){ |
43 | Node left_lca = findLCA(root.left, node1, node2); |
44 | Node right_lca = findLCA(root.right, node1, node2); |
46 | if (left_lca != null && right_lca != null ){ |
50 | return left_lca != null ? left_lca : right_lca; |
53 | public static int distanceNodes(Node root, int node1, int node2){ |
54 | Node lca = findLCA(root, node1, node2); |
55 | int dis_lca = findLevel(root, lca.key); |
56 | int dis1 = findLevel(root, node1); |
57 | int dis2 = findLevel(root, node2); |
58 | return dis1 + dis2 - 2 *dis_lca; |
61 | public static void main(String args[]){ |
62 | Node root = new Node( 1 ); |
63 | root.left = new Node( 2 ); |
64 | root.right = new Node( 3 ); |
65 | root.left.left = new Node( 4 ); |
66 | root.left.right = new Node( 5 ); |
67 | root.right.left = new Node( 6 ); |
68 | root.right.right = new Node( 7 ); |
69 | root.right.left.right = new Node( 8 ); |
71 | System.out.println( "Dist(8,7) = " + distanceNodes(root, 8 , 7 )); |
72 | System.out.println( "Dist(8,3) = " + distanceNodes(root, 8 , 3 )); |
73 | System.out.println( "Dist(8,3) = " + distanceNodes(root, 8 , 2 )); |
时间复杂度为 O(N).