Closest Coprime Ancestor

Hard
0/120
Average time to solve is 50m
5 upvotes
Asked in company
Apple

Problem statement

You are given an integer array, ‘NODES’ and a 2 - D array, ‘EDGES’ to represent a tree (i.e. a connected undirected graph) consisting of ‘N’ nodes (numbered from 0 to N - 1) and exactly (N - 1) edges where the EDGES[ i ] = {Ui, Vi} represents an edge between the ‘U’th and ‘V’th node. Each node has a value associated with it, stored in the ‘NODES’ array where ‘NODES[ i ]’ represents the ‘i’th node’s value.

Your task is to return an ‘N’ size array, ‘RESULT’, where RESULT[ i ] = the closest ancestor to ‘i’th node such that NODES[ i ] and NODES[RESULT[ i ]] are coprime, else if no such ancestor found, RESULT[ i ] = -1.

Note :

1) The value associated with the ‘ROOT’ node of the tree is considered zero.
2) Two integers ‘A’ and ‘B’ are coprime if the only positive integer that evenly divides (is a divisor of) both of them is 1, i.e., GCD(A, B) = 1 where GCD(A, B) is the greatest common divisor of ‘A’ and ‘B’.
3) Any node on the shortest path from ‘i’th node to the root is the ancestor of the ‘i’th node.
4) A node is not considered an ancestor of itself.
5) A graph is said to be a connected undirected graph if all the edges are bidirectional and there is a path between every pair of distinct vertices of the graph.
Detailed explanation ( Input/output format, Notes, Images )

Input Format :

The first line of input contains an integer 'T' representing the number of test cases.

The first line of each test case contains an integer ‘N’ representing the number of nodes in the tree.

The second line of each test case contains ‘N’ space-separated integers representing the elements of the ‘NODES’ array.

The next ‘N - 1’ lines of each test case contain two space-separated integers, ‘U’ and ‘V’, representing an edge between ‘U’ and ‘V’. 

Output Format :

For each test case, print a ‘N’ size array, ’RESULT’ where RESULT[i] = the closest ancestor to ‘i’th node such that NODES[ i ] and NODES[RESULT[ i ]] are coprime, else if no such ancestor found, RESULT[ i ] = -1.

The output of each test case will be printed in a separate line.

Constraints :

1 <= T <= 5
1 <=  N <= 2000
|EDGES[ i ]| = 2
1 <= NODES[ i ] <= 20
EDGES[ i ] = {Ui, Vi} where 0 <= Ui, Vi < N
Ui != Vi

Where ‘|EDGES[ i ]| is the length of ‘i’ the array in ‘EDGES’, ‘NODES[ i ]’ is the ‘i’th element in the ‘NODES’ array, ‘EDGES[ i ]’ is the ‘i’th array of two integers ‘Ui’ and ‘Vi’ in the 2 - D array, ‘EDGES’.

Time limit: 1 sec

Note :

 You do not need to print anything, it has already been taken care of. Just implement the given function.

Sample Input 1 :

2
4
8 7 4 5
0 1
0 2
2 3
5
2 5 4 7 2
0 2
0 3
0 4
1 2

Sample Output 1 :

-1 0 -1 2
-1 2 -1 0 -1

Explanation Of Sample Output 1 :

Test Case 1 :  

Given input can be represented as the above tree where the node’s value is in parenthesis.
Node 0 has no coprime ancestor. So, RESULT[ 0 ] = -1.
Node 1 has only one coprime ancestor, i.e., 0. So, RESULT[ 1 ] = 0.
Node 2 has no coprime ancestor. So, RESULT[ 2 ] = -1.
Node 3 has two coprime ancestors, 2 and 0. Since node 2 is closest to node 3, therefore, RESULT[ 3 ] = 2.

Test Case 2 : 

Given input can be represented as the above tree where the node’s value is in parenthesis.
Node 0 has no coprime ancestor. So, RESULT[ 0 ] = -1.
Node 1 has two coprime ancestors, 2 and 0. Since node 2 is closest to node 1, therefore, RESULT[ 1 ] = 2.
Node 2 has no coprime ancestor. So, RESULT[ 2 ] = -1.
Node 3 has only one coprime ancestor, i.e., 0. So, RESULT[ 3 ] = 0.
Node 4 has no coprime ancestor. So, RESULT[ 4 ] = -1.

Sample Input 2 :

1
6
7 4 5 2 6 8
0 2
0 4
1 2
1 3
2 5

Sample Output 2 :

-1 2 0 2 0 2
Hint

Use brute force approach to traverse the tree and calculate the closest coprime ancestor for each node.

Approaches (2)
Brute Force

The idea is to use the brute force approach to traverse the tree using DFS. At every node, we will go through all of its ancestors and check if they are coprime, and update the ‘RESULT’ array.

For this purpose, we will first build an adjacency list using ‘EDGES’ and then perform the DFS.

 

Algorithm:

  • Declare a vector of integers, ‘RESULT’ of size ‘N’ to store the closest coprime ancestor for every node.
  • Declare a vector of integers, ‘ANCESTORS’ to store the list of ancestors for every node.
  • Declare a vector of vector of integers, ‘ADJLIST’ to store the adjacency list representation of the given tree.
  • Run a loop for every vector of integers, ‘EDGE’ in the ‘EDGES’.
    • Push ‘EDGE[ 1 ]’ in the ‘ADJLIST[EDGE[ 0 ]]’.
    • Push ‘EDGE[ 0 ]’ in the ‘ADJLIST[EDGE[ 1 ]]’.
  • Call the ‘dfs’ function.
  • In the end, return ‘RESULT’.

 

Description of ‘dfs’ function :

This function will take six parameters:

  • NODES: A vector of integers representing the values associated with every node.
  • ADJLIST: A vector of vector of integers representing the adjacency list of the given tree.
  • ANCESTORS: A vector of integers representing the list of ancestors for every node.
  • CURRENT: An integer representing the current node for which the closest coprime ancestor has to be found.
  • PARENT: An integer representing the parent of the ‘CURRENT’ node.
  • RESULT: a vector of integers to store the closest coprime ancestor for every node.

void dfs(NODES, ADJLIST, ANCESTORS, CURRENT, PARENT, RESULT):

  • Assign -1 to the ‘RESULT[CURRENT]’ indicating ‘CURRENT’ has no coprime ancestor.
  • Run a loop for every ‘ANCESTOR’ in the ‘ANCESTORS’.
  • Declare a variable ‘VALUEOFANCESTOR’ and assign ‘NODES[ ANCESTOR ]’ to it.
  • Declare a variable ‘VALUEOFCURRENT’ and assign ‘NODES[ CURRENT ]’ to it.
  • If GCD of ‘VALUEOFANCESTOR’ and ‘VALUEOFCURRENT’ that shows that we found a coprime ancestor of ‘CURRENT’ node. So,
    • Assign ‘ANCESTOR’ to ‘RESULT[ CURRENT ]’.
  • Push ‘CURRENT’ to the ‘ANCESTORS’.
  • Run a loop for every ‘CHILDNODE’ in ‘ADJLIST[ CURRENT ]’.
    • If ‘CHILDNODE’ is not equal to ‘PARENT’
      • Call ‘dfs’ by updating ‘CURRENT’ as ‘CHILDNODE’ and ‘PARENT’ as ‘CURRENT’.
  • Pop the last element from ‘ANCESTORS’.
Time Complexity

O(N ^ 2), where ‘N’ is the number of nodes in the tree.

 

A usual DFS traversal takes O(N + E) time where ‘N’ is the number of nodes, and ‘E’ is the number of edges in the tree. But in a tree, E = N - 1; therefore, the time complexity of a usual DFS traversal of a tree is O(N + N - 1) = O(N).

For each node, we are processing all its ancestors which is an O(N) operation in the worst case.

Finding GCD of two numbers, ‘A’ and ‘B’ takes O(log(M)) time, where M = max(A, B).

Then the time complexity will become O(N) * O(N) * O(log(M)) = O((N ^ 2) * log(M)).

But the maximum node value can be 20 only, so log(20) = 4 (approx).

Therefore, overall time complexity = O((N ^ 2) * 4) = O(N ^ 2).

Space Complexity

O(N), where ‘N’ is the number of nodes in the tree.

 

Since ‘ADJLIST’ requires O(N + E) space where ‘N’ is the number of nodes and ‘E’ is the number of edges in the tree. But in a tree, E = N - 1, therefore, the space requirement of an ‘adjList’ is O(N + N - 1) = O(N).

Also, O(N) space is required for the ‘ANCESTORS’ array and recursive call stack.

Therefore, overall space complexity = O(N) + O(N) + O(N) = O(N).

Code Solution
(100% EXP penalty)
Closest Coprime Ancestor
Full screen
Console