This is an interview question. I have an undirected graph with n
nodes from 1 to n
. There are no cycles in the graph.
Graph is represented using 2 lists, from
list and to
list. An edge connects the points from[i] to to[i]
.
Suppose the maximum distance between any two nodes is max
.
Now a node is considered primary if it lies on the simple path between two nodes u
and v
such that the distance between u
and v
is equal to max
.
All other nodes are secondary.
Now find the sum of indices of all the secondary nodes. This sum is the expected solution.
Example n = 4
from = [1, 1, 2]
to = [2, 3, 4]
Answer : 0
Explanation:
The maximum distance between any two nodes is 3, the pair (3, 4). All the nodes on the path 3 --> 1 --> 2 --> 4 are primary. Since no node is secondary, the answer is 0.
Other test cases are :
node = 6
from = [1,1,1,2,3]
to [2,3,4,5,6]
Answer :
4
nodes = 5
from = [1,1,2,2]
to [2,3,4,5]
Answer :
0
Here is my code which I tried:
import java.util.*;
public class Main {
public static long solution(int n, List<Integer> from, List<Integer> to) {
List<List<Integer>> adjList = new ArrayList<>();
for (int i = 0; i <= n; i++) {
adjList.add(new ArrayList<>());
}
// Build adjacency list
for (int i = 0; i < from.size(); i++) {
adjList.get(from.get(i)).add(to.get(i));
adjList.get(to.get(i)).add(from.get(i));
}
// First DFS/BFS to find the farthest node from any node (let's start with node 1)
int[] dist = bfs(1, n, adjList);
int farthest1 = findFarthestNode(dist);
// Second DFS/BFS to find the farthest node from farthest1
dist = bfs(farthest1, n, adjList);
int farthest2 = findFarthestNode(dist);
int mx = dist[farthest2];
// DFS/BFS to find all primary nodes on the path from farthest1 to farthest2
Set<Integer> primaryNodes = findPrimaryNodes(farthest1, farthest2, n, adjList);
// Sum of secondary influencer indices
long secondarySum = 0;
for (int i = 1; i <= n; i++) {
if (!primaryNodes.contains(i)) {
secondarySum += i;
}
}
return secondarySum;
}
// BFS function to calculate distances from a start node
private static int[] bfs(int start, int n, List<List<Integer>> adjList) {
int[] dist = new int[n + 1];
Arrays.fill(dist, -1);
Queue<Integer> queue = new LinkedList<>();
queue.add(start);
dist[start] = 0;
while (!queue.isEmpty()) {
int node = queue.poll();
for (int neighbor : adjList.get(node)) {
if (dist[neighbor] == -1) {
dist[neighbor] = dist[node] + 1;
queue.add(neighbor);
}
}
}
return dist;
}
// Function to find the farthest node given distances
private static int findFarthestNode(int[] dist) {
int maxDist = 0;
int node = 0;
for (int i = 1; i < dist.length; i++) {
if (dist[i] > maxDist) {
maxDist = dist[i];
node = i;
}
}
return node;
}
// DFS/BFS to find all primary nodes on the path from farthest1 to farthest2
private static Set<Integer> findPrimaryNodes(int farthest1, int farthest2, int n, List<List<Integer>> adjList) {
Set<Integer> primaryNodes = new HashSet<>();
Stack<Integer> stack = new Stack<>();
boolean[] visited = new boolean[n + 1];
int[] parent = new int[n + 1];
stack.push(farthest1);
visited[farthest1] = true;
parent[farthest1] = -1;
while (!stack.isEmpty()) {
int node = stack.pop();
for (int neighbor : adjList.get(node)) {
if (!visited[neighbor]) {
parent[neighbor] = node;
visited[neighbor] = true;
stack.push(neighbor);
if (neighbor == farthest2) {
// Trace back to find the path from farthest2 to farthest1
int current = farthest2;
while (current != -1) {
primaryNodes.add(current);
current = parent[current];
}
return primaryNodes;
}
}
}
}
return primaryNodes;
}
public static void main(String[] args) {
List<Integer> from = Arrays.asList(1, 1, 2);
List<Integer> to = Arrays.asList(2, 3, 4);
System.out.println(solution(4, from, to)); // Output: 0
from = Arrays.asList(1, 1, 1, 2, 3);
to = Arrays.asList(2, 3, 4, 5, 6);
System.out.println(solution(6, from, to)); // Output: 4
from = Arrays.asList(1, 1, 2, 2);
to = Arrays.asList(2, 3, 4, 5);
System.out.println(solution(5, from, to)); // Output: 0
}
}
I tried BFS
approach, my code fails for 3rd test case, instead of giving result as 0, it is returning 5.
Also it was asked in hackerrank interview, when I tried this approach, I was able to solve only 4 test cases out of 15.
What is the correct approach to solve this problem.
3
An undirected graph with no cycles is a forest, each component of which is a tree. For each component, we can calculate the length of the longest path that goes through each node in linear time with two DFS traversals. At the end, we can simply compare the maximum path through each node with the global maximum.
public static long solution(int n, List<Integer> from, List<Integer> to) {
var adj = Stream.<List<Integer>>generate(ArrayList::new).limit(n + 1).toList();
for (int i = 0; i < to.size(); i++) {
adj.get(from.get(i)).add(to.get(i));
adj.get(to.get(i)).add(from.get(i));
}
int[] up = new int[n + 1], down = new int[n + 1];
var vis = new boolean[n + 1];
// creating new object for easy recursion within the solution method
return new Object() {
int dfs(int u) {
vis[u] = true;
int deep = 0, deep2 = 0;
for (int v : adj.get(u))
if (!vis[v]) {
up[v] = Math.max(up[u], deep) + 1;
int path = dfs(v) + 1;
if (path >= deep) {
deep2 = deep;
deep = path;
} else if (path > deep2) deep2 = path;
}
down[u] = deep + deep2;
return deep;
}
int dfs2(int u, int p) {
int deep = 0, deep2 = 0;
for (int i = adj.get(u).size() - 1; i >= 0; i--) {
int v = adj.get(u).get(i);
if (v != p) {
up[v] = Math.max(up[v], Math.max(up[u], deep) + 1);
int path = dfs2(v, u) + 1;
if (path >= deep) {
deep2 = deep;
deep = path;
} else if (path > deep2) deep2 = path;
}
}
up[u] += deep;
return deep;
}
long solve() {
int maxPath = 0;
for (int i = 1; i <= n; ++i) {
if (!vis[i]) {
dfs(i);
dfs2(i, i);
}
maxPath = Math.max(maxPath, Math.max(up[i], down[i]));
}
long ans = 0;
for (int i = 1; i <= n; ++i)
if (Math.max(up[i], down[i]) < maxPath) ans += i;
return ans;
}
}.solve();
}