Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
JavaScript group array - find the sets of numbers that can be traveled to using the edges defined
Consider the following input and output arrays:
const input = ["0:3", "1:3", "4:5", "5:6", "6:8"]; const output = [ [0, 1, 3], [4, 5, 6, 8] ];
Considering each number as a node in a graph, and each pairing x:y as an edge between nodes x and y, we are required to find the sets of numbers that can be traveled to using the edges defined.
In graph theory terms, we need to find the distinct connected components within such a graph. For instance, in the above arrays, there is no way to travel from 4 to 0 so they are in different groups, but there is a way to travel from 1 to 0 (by way of 3) so they are in the same group.
We need to write a JavaScript function that constructs the desired output from the given input by grouping nodes that can reach each other through the available edges.
Understanding Connected Components
Union-Find Solution
The most efficient approach uses the Union-Find data structure to track connected components:
const input = ["0:3", "1:3", "4:5", "5:6", "6:8"];
const findConnectedComponents = (edges) => {
const parent = {};
// Find root parent with path compression
const find = (x) => {
if (!(x in parent)) parent[x] = x;
if (parent[x] !== x) {
parent[x] = find(parent[x]);
}
return parent[x];
};
// Union two nodes
const union = (x, y) => {
const rootX = find(x);
const rootY = find(y);
if (rootX !== rootY) {
parent[rootX] = rootY;
}
};
// Process all edges
edges.forEach(edge => {
const [a, b] = edge.split(':').map(Number);
union(a, b);
});
// Group nodes by their root parent
const groups = {};
Object.keys(parent).forEach(node => {
const root = find(parseInt(node));
if (!groups[root]) groups[root] = [];
groups[root].push(parseInt(node));
});
return Object.values(groups).map(group => group.sort((a, b) => a - b));
};
console.log(findConnectedComponents(input));
[ [ 0, 1, 3 ], [ 4, 5, 6, 8 ] ]
Alternative: Depth-First Search
Another approach uses DFS to traverse connected components:
const findConnectedComponentsDFS = (edges) => {
// Build adjacency list
const graph = {};
edges.forEach(edge => {
const [a, b] = edge.split(':').map(Number);
if (!graph[a]) graph[a] = [];
if (!graph[b]) graph[b] = [];
graph[a].push(b);
graph[b].push(a);
});
const visited = new Set();
const components = [];
const dfs = (node, component) => {
visited.add(node);
component.push(node);
if (graph[node]) {
graph[node].forEach(neighbor => {
if (!visited.has(neighbor)) {
dfs(neighbor, component);
}
});
}
};
// Find all nodes
const allNodes = new Set();
edges.forEach(edge => {
const [a, b] = edge.split(':').map(Number);
allNodes.add(a);
allNodes.add(b);
});
// Start DFS from unvisited nodes
allNodes.forEach(node => {
if (!visited.has(node)) {
const component = [];
dfs(node, component);
components.push(component.sort((a, b) => a - b));
}
});
return components;
};
console.log(findConnectedComponentsDFS(input));
[ [ 0, 1, 3 ], [ 4, 5, 6, 8 ] ]
Comparison
| Method | Time Complexity | Space Complexity | Best For |
|---|---|---|---|
| Union-Find | O(E × ?(V)) | O(V) | Dynamic connectivity |
| DFS | O(V + E) | O(V + E) | Simple implementation |
Conclusion
Both Union-Find and DFS effectively solve the connected components problem. Union-Find is more efficient for repeated queries, while DFS offers simpler implementation for one-time analysis.
