Google – Average Length of City Path
给n个城市,和n – 1条edge, 这些edges可以保证所有城市都两两互通,每条edge都有长度,求所有城市两两之间path的长度之和,再除以path的数量得到的平均数。
[Solution]
第一种解法就是brute force,O(n^2) time
第二种解法来自一亩三分地,可以在O(n)时间内解决问题。思路非常tricky,类似于Leetcode 310 Minimum Height Tree的解法。
因为题目明确给出了有n个node和n – 1条edges,看到这两个数字应该很本能的反应出这道题和tree拖不了关系。但是Brute Force的解法并没有利用到这个条件。而O(n)的解法正是利用构建Minimum Height Tree来解决问题。下面是算法思路:
(1)算degree
(2)逐层删leaf node来找root。就是Minimum Height Tree的算法。
(3)在删leaf node的过程中多做两件事:建tree和计算sub tree size(包括该节点本身)。如果在第(2)步有两个root,随便选一个作为root,另一个作为子节点就好。这里的主要目的是建Tree.
(4)如果总共有N个结点,当前结点v的sub tree size为K (包括v本身),那么连接v和其parent的那条edge就会被遍历K * (N-K)次。
这是因为如果以v为分界把这个graph分为两部分,一部分有K个点,另一部分为N-K个点。因为每对Pair都需要走一遍,也就是左边的K个点中的任何一个都要去找右边的N-K个点。又因为树的特性,每对pair之间只可能有一条path,所以v到其parent之间的这条edge必定会被遍历K * (N-K)次。
(5)构建完tree,证明完(4),剩下的只需要对tree做一个dfs traversal,就可以得到总的path sum。再除以n-1就可以得到答案了。
http://www.1point3acres.com/bbs/thread-139392-1-1.html
Read full article from Google – Average Length of City Path
给n个城市,和n – 1条edge, 这些edges可以保证所有城市都两两互通,每条edge都有长度,求所有城市两两之间path的长度之和,再除以path的数量得到的平均数。
[Solution]
第一种解法就是brute force,O(n^2) time
第二种解法来自一亩三分地,可以在O(n)时间内解决问题。思路非常tricky,类似于Leetcode 310 Minimum Height Tree的解法。
因为题目明确给出了有n个node和n – 1条edges,看到这两个数字应该很本能的反应出这道题和tree拖不了关系。但是Brute Force的解法并没有利用到这个条件。而O(n)的解法正是利用构建Minimum Height Tree来解决问题。下面是算法思路:
(1)算degree
(2)逐层删leaf node来找root。就是Minimum Height Tree的算法。
(3)在删leaf node的过程中多做两件事:建tree和计算sub tree size(包括该节点本身)。如果在第(2)步有两个root,随便选一个作为root,另一个作为子节点就好。这里的主要目的是建Tree.
(4)如果总共有N个结点,当前结点v的sub tree size为K (包括v本身),那么连接v和其parent的那条edge就会被遍历K * (N-K)次。
这是因为如果以v为分界把这个graph分为两部分,一部分有K个点,另一部分为N-K个点。因为每对Pair都需要走一遍,也就是左边的K个点中的任何一个都要去找右边的N-K个点。又因为树的特性,每对pair之间只可能有一条path,所以v到其parent之间的这条edge必定会被遍历K * (N-K)次。
(5)构建完tree,证明完(4),剩下的只需要对tree做一个dfs traversal,就可以得到总的path sum。再除以n-1就可以得到答案了。
class
Solution2 {
int
sum =
0
;
int
n;
public
int
averagePathLength(
int
n,
int
[][] graph) {
if
(n <=
1
) {
return
0
;
}
this
.n = n;
// get degree of every node
Map<Integer, Integer> degree =
new
HashMap<>();
for
(
int
i =
0
; i < n; i++) {
for
(
int
j =
0
; j < n; j++) {
if
(graph[i][j] !=
0
) {
degree.put(i, degree.getOrDefault(i,
0
) +
1
);
degree.put(j, degree.getOrDefault(j,
0
) +
1
);
}
}
}
// Build the tree
TNode root = buildTree(degree, graph);
// dfs traversal to get the path sum
dfs(root);
return
sum / (n -
1
);
}
private
void
dfs(TNode root) {
if
(root ==
null
) {
return
null
;
}
for
(TNode child : root.children) {
sum += child.size * (n - child.size) * graph[root.val][child.val];
dfs(child);
}
}
private
TNode buildTree(Map<Integer, Integer> degree,
int
[][] graph) {
Map<Integer, TNode> nodeMap =
new
HashMap<>();
for
(
int
i =
0
; i < n; i++) {
nodeMap.put(i,
new
TNode(i));
}
Queue<Integer> queue =
new
LinkedList<>();
for
(
int
v : degree) {
if
(degree.get(v) ==
1
) {
queue.add(v);
nodeMap.get(v).size +=
1
;
}
}
for
(
int
v : queue) {
degree.remove(v);
}
while
(
true
) {
int
size = queue.size();
for
(
int
i =
0
; i < size; i++) {
int
curr = queue.poll();
int
currSize = nodeMap.get(curr).size;
for
(
int
adj =
0
; adj < n; adj++) {
if
(graph[curr][adj] !=
0
) {
nodeMap.get(adj).children.add(curr);
nodeMap.get(adj).size += currSize;
degree.put(adj, degree.get(adj) -
1
);
if
(degree.get(adj) ==
1
) {
queue.offer(adj);
}
}
}
}
for
(
int
v : queue) {
degree.remove(v);
}
if
(degree.isEmpty()) {
break
;
}
}
if
(queue.size() >
1
) {
int
root1 = queue.poll();
int
root2 = queue.poll();
nodeMap.get(root1).children.add(root2);
nodeMap.get(root1).size += nodeMap.get(root2).size;
return
nodeMap.get(root1);
}
return
nodeMap.get(queue.poll());
}
private
class
TNode {
int
val;
List<TNode> children;
int
size;
TNode(
int
val) {
this
.val = val;
this
.children =
new
ArrayList<>();
}
}
}
Read full article from Google – Average Length of City Path