Leetcode.com problem 834: Sum of Distances in Tree
James S. Plank
Sat Dec 24 01:22:33 EST 2022
In case Leetcode's servers are down
You are to write a method in the class Solution with the following
prototype:
vector<int> sumOfDistancesInTree(int n, vector <vector <int> >&edges);
|
- You are dealing with an undirected tree with n nodes.
- The nodes are labeled 0 to n-1.
- Each entry in edges is a vector with two elements that defines an edge in the
tree.
- Your return value is a vector with n nodes.
- Value i of the return value is equal to the sum of the distances between
node i and every other node in the tree.
Here's an example tree (which is example 1):
0
/ \
/ \
1 2
/|\
/ | \
3 4 5
|
The answer is { 8, 12, 6, 10, 10, 10 }. To explain a little, consider node 0. Its distance
to nodes 1 and 2 is one, and its distance to nodes 3, 4 and 5 is two. So the sum of its
distances is 1+1+2+2+2 = 8.
Constraints: The tree has up to 30,000 nodes.
The skeleton program
If you give it no command line arguments, then it will read the edges on standard input.
If you give it a positive number on the command line, then it will generate a random problem.
If the number is a multiple of 5, the problem will be small. Otherwise, the problem will be
of a random size less than or equal to 30,000. If you give it a negative number, then it
will print the edges before calling the solution. For example:
UNIX> a.out 5 // When the seed is a multiple of 5, the tree is small.
15 21 13 19 23 17 21 13
UNIX> a.out -5 // When you give it a negative number, it prints the edges.
5 2
7 2
0 7
4 5
3 2
1 0
6 0
15 21 13 19 23 17 21 13
UNIX>
Hints
It's not a bad idea to work through the example above before moving on.
The first thing to realize is that any node can be the root of the tree.
It doesn't affect the answer. To illustrate, suppose we make node 5 the
root of the tree:
5
|
2
/|\
/ | \
0 3 4
|
1
|
You'll note that the answer is the same. So let's
do a few things to start:
- Arbitrarily assign node 0 to be the root of the tree.
- Build adjacency lists for each node. When I did this, I didn't
worry about who was the parent of whom yet. For each edge in
edges, I added each node to the other's adjacency list.
So, for example, in the tree above, node 2's adjacency list is
{ 0, 3, 4, 5 }.
I don't know how to help you think about constructing an answer for
problems like these. Your first thought should be: With 30,000 nodes,
my solution has to be O(n) or O(n log n) at the worst.
DFS, BFS and tree traversals are all O(n) so let's start
there. What quantities can we store in each node that we can
set with one of those algorithms?
Task 1 -- Assigning Parents
The first, most obvious one is assigning parents of each node. You can
do that with a tree traversal. Make that your first task. To help
you test, I have two files.
ex1.txt has the tree above.
ex4.txt has the tree below:
0
/|\
/ | \
1 3 2
/| / \
/ | / \
4 8 14 15
/|\ /| /|\
/ | \ / | / | \
5 6 7 9 10 / | \
11 12 13
|
I added a Parent vector to the Solution class, and then
wrote a recursive method to set the parents. When traversing a node's adjacency
list, I simply skipped the parent and didn't make a recursive call on the parent
(I do this in all of my tree traversals).
void set_parents(int node);
|
I tested it and put the outputs into
parents1.txt
and
parents4.txt. Test yourself with these
files.
parents1.txt
0: -1
1: 0
2: 0
3: 2
4: 2
5: 2
|
parents4.txt
0: -1
1: 0
2: 0
3: 0
4: 1
5: 4
6: 4
7: 4
8: 1
9: 14
10: 14
11: 15
12: 15
13: 15
14: 2
15: 2
|
Task 2 -- Setting Sizes
A second simple task is to create a vector Size and setting Size[i] to the
number of nodes in the tree rooted by node i. This is a post-order traversal.
Here's output for the two trees:
sizes1.txt
0: 6
1: 1
2: 4
3: 1
4: 1
5: 1
|
sizes4.txt
0: 16
1: 6
2: 8
3: 1
4: 4
5: 1
6: 1
7: 1
8: 1
9: 1
10: 1
11: 1
12: 1
13: 1
14: 3
15: 4
|
Task 3 -- sum of distances to the nodes in your tree
Next, I tried to think of something I could do with a postorder traversal.
The task I came up with is to sum all of the distances of a node to nodes in
the tree that it roots. For example, for node 4 in the ex4.txt, this
sum is three. For node 1, the sum is 8 (Distance 1 to nodes 4 and 8. Distance
2 to nodes 5, 6 and 7.)
How do we do this with a postorder traversal? Work through the example of node
1 above. The sums for nodes 5, 6, 7 and 8 are zero. Node 4 has a sum of 3.
When we calculate the sum for node one, we can do it as follows:
- Node 4's sum is 3, and there are 4 nodes in its tree. Therefore, from node 1,
there are four extra edges to count. The sum of distances to nodes in node 4's tree
is 3+4 = 7.
- Node 8's sum is 0 and there is one node in its tree. Therefore, from node 1,
there is one extra edge to count.
The sum of distances to nodes in node 8's tree is 0+1 = 1.
-
So the sum for node 1 is 7+1 = 8.
Go ahead and write this code. Here are the answers for the two trees. I called
the array Below, since it is the sum of distances to nodes below a given node.
If you are having
problems with this, walk though how you calculate the values for nodes 14, 15, 2 and 0 above.
below1.txt
0: 8
1: 0
2: 3
3: 0
4: 0
5: 0
|
below4.txt
0: 35
1: 8
2: 12
3: 0
4: 3
5: 0
6: 0
7: 0
8: 0
9: 0
10: 0
11: 0
12: 0
13: 0
14: 2
15: 3
|
Task 4 -- calculating the answer
First, note that Below[0] is in fact the answer for node 0. That's because all of the
nodes are in node 0's tree.
Now, let's consider node 1 in ex4.txt. I'm going to redraw the tree in two
colors.
0
/|\
/ | \
1 3 2
/| / \
/ | / \
4 8 14 15
/|\ /| /|\
/ | \ / | / | \
5 6 7 9 10 / | \
11 12 13
|
We can calculate the answer for node 1 by counting the sum of distances to
the blue nodes, and then adding the sum of distances to the red nodes.
The sum of distances to the blue nodes is simple -- it's Below[1].
To calculate the red nodes, let's count the sum of distances from node 0
to the red nodes. That's going to be the following equation:
SumRed0 = Answer[0] - (Below[1] + Size[1])
The sum of distances from node 1 to the red nodes (which we'll call
SumRed1) will be SumRed0
plus the number of red nodes. What is that number? It is: (Number of nodes
in the tree) - Size[1]).
So:
SumRed1 = SumRed0 + #Nodes - Size[1].
Put it all together:
Answer[1] = Below[1] + SumRed1
Answer[1] = Below[1] + SumRed0 + #Nodes - Size[1]
Answer[1] = Below[1] + Answer[0] - (Below[1] + Size[1]) + #Nodes - Size[1]
Answer[1] = Below[1] + Answer[0] - Below[1] - Size[1] + #Nodes - Size[1]
Answer[1] = Answer[0] - 2*Size[1] + #Nodes
Answer[1] = 35 - 6*2 + 16 = 39
Similarly:
Answer[4] = Answer[1] - 2*Size[4] + #Nodes
Answer[1] = 39 - 2*4 + 16 = 47
You do this with a preorder traversal. Here are the answers:
answers1.txt
0: 8
1: 12
2: 6
3: 10
4: 10
5: 10
|
answers4.txt
0: 35
1: 39
2: 35
3: 49
4: 47
5: 61
6: 61
7: 61
8: 53
9: 59
10: 59
11: 57
12: 57
13: 57
14: 45
15: 43
|
I hope that gives you all of the pieces to the puzzle, so that you can solve the
problem!