In an undirected graph, a connected component is a subgraph in which any two vertices are connected to each other by paths, and which is connected to no additional vertices in the graph.
In simpler terms, a connected component is a group of vertices that are all reachable from each other.
Given an undirected graph, find all connected components in the graph.
Example:
Graph: A -- B -- C
D -- E -- F
G
Connected components: [A, B, C], [D, E, F], [G]
Here's an implementation of the connected components algorithm using BFS:
O(V + E), where V is the number of vertices and E is the number of edges in the graph.
O(V), where V is the number of vertices in the graph.
A classic application of the connected components pattern is the Number of Islands problem, where we need to count the number of islands in a 2D grid.
Learn how to use BFS to find all connected components in an undirected graph.
In an undirected graph, a connected component is a subgraph in which any two vertices are connected to each other by paths, and which is connected to no additional vertices in the graph.
In simpler terms, a connected component is a group of vertices that are all reachable from each other.
Example:
Graph:
A -- B -- C
D -- E -- F
G
Connected components: [A, B, C], [D, E, F], [G]
Explanation: This graph has three connected components. The first component contains vertices A, B, and C, which are all reachable from each other. The second component contains D, E, and F. The third component contains only G, which is not connected to any other vertex.
BFS guarantees that all vertices reachable from a starting vertex will be visited. This makes it perfect for finding all vertices in a connected component.
BFS has a time complexity of O(V + E), which is optimal for traversing a graph. It visits each vertex and edge exactly once.
The algorithm for finding connected components using BFS is straightforward: run BFS from each unvisited vertex to find all vertices in its component.
Initialize a set to keep track of visited vertices and an array to store all connected components.
For each unvisited vertex in the graph, run BFS to find all vertices in its connected component.
During BFS, mark all visited vertices and add them to the current component. This ensures each vertex is part of exactly one component.
Here's an implementation of the connected components algorithm using BFS:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768function findConnectedComponents(graph) { // Set to keep track of visited vertices const visited = new Set(); // Array to store all connected components const components = []; // For each vertex in the graph for (const vertex in graph) { // If this vertex has not been visited yet if (!visited.has(vertex)) { // Find all vertices in the same component as this vertex const component = bfsComponent(graph, vertex, visited); // Add this component to the list of components components.push(component); } } return components;} function bfsComponent(graph, startVertex, visited) { // Queue for BFS const queue = [startVertex]; // Mark the start vertex as visited visited.add(startVertex); // Array to store vertices in this component const component = [startVertex]; // While there are vertices in the queue while (queue.length > 0) { // Dequeue a vertex from the queue const currentVertex = queue.shift(); // Get all adjacent vertices of the dequeued vertex for (const neighbor of graph[currentVertex]) { // If this adjacent vertex has not been visited if (!visited.has(neighbor)) { // Mark it as visited and enqueue it visited.add(neighbor); queue.push(neighbor); // Add it to this component component.push(neighbor); } } } return component;} // Example usage:const graph = { 'A': ['B'], 'B': ['A', 'C'], 'C': ['B'], 'D': ['E'], 'E': ['D', 'F'], 'F': ['E'], 'G': []}; const components = findConnectedComponents(graph);console.log(components);// Output: [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]
Key Insight: We run BFS from each unvisited vertex to find all vertices in its connected component. By marking vertices as visited, we ensure that each vertex is part of exactly one component.
O(V + E), where V is the number of vertices and E is the number of edges in the graph.
Explanation: We visit each vertex once (O(V)) and explore each edge once (O(E)). Even though we run BFS multiple times, each vertex and edge is processed exactly once across all BFS calls.
O(V), where V is the number of vertices in the graph.
Explanation: We need to store the visited set (O(V)) and the queue for BFS (O(V) in the worst case). Additionally, we need O(V) space for storing the components. Overall, the space complexity is O(V).
Counting the number of islands in a 2D grid, where each island is a connected component of land cells.
Finding the number of friend circles in a social network, where each circle is a connected component of friends.
Identifying connected regions in an image for image segmentation or object recognition.
A classic application of the connected components pattern is the Number of Islands problem, where we need to count the number of islands in a 2D grid. An island is a group of connected land cells (represented by '1'), surrounded by water cells (represented by '0').
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162function numIslands(grid) { if (!grid || grid.length === 0) { return 0; } const rows = grid.length; const cols = grid[0].length; let count = 0; // Directions: up, right, down, left const directions = [[-1, 0], [0, 1], [1, 0], [0, -1]]; // Function to check if a cell is valid and is land function isValid(row, col) { return row >= 0 && row < rows && col >= 0 && col < cols && grid[row][col] === '1'; } // BFS to mark all connected land cells as visited function bfs(row, col) { const queue = [[row, col]]; grid[row][col] = '0'; // Mark as visited by changing '1' to '0' while (queue.length > 0) { const [currentRow, currentCol] = queue.shift(); // Check all four directions for (const [dr, dc] of directions) { const newRow = currentRow + dr; const newCol = currentCol + dc; if (isValid(newRow, newCol)) { queue.push([newRow, newCol]); grid[newRow][newCol] = '0'; // Mark as visited } } } } // Iterate through each cell in the grid for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { // If we find a land cell, start BFS and increment count if (grid[i][j] === '1') { count++; bfs(i, j); } } } return count;} // Example usage:const grid = [ ['1', '1', '0', '0', '0'], ['1', '1', '0', '0', '0'], ['0', '0', '1', '0', '0'], ['0', '0', '0', '1', '1']]; const islands = numIslands(grid);console.log(islands); // Output: 3
How it works: We iterate through each cell in the grid. When we find a land cell ('1'), we start BFS from that cell to mark all connected land cells as visited (by changing them to '0'). Each time we start a new BFS, we've found a new island, so we increment our count.
In an undirected graph, a connected component is a subgraph in which any two vertices are connected to each other by paths, and which is connected to no additional vertices in the graph.
In simpler terms, a connected component is a group of vertices that are all reachable from each other.
Given an undirected graph, find all connected components in the graph.
Example:
Graph: A -- B -- C
D -- E -- F
G
Connected components: [A, B, C], [D, E, F], [G]
Here's an implementation of the connected components algorithm using BFS:
O(V + E), where V is the number of vertices and E is the number of edges in the graph.
O(V), where V is the number of vertices in the graph.
A classic application of the connected components pattern is the Number of Islands problem, where we need to count the number of islands in a 2D grid.
Learn how to use BFS to find all connected components in an undirected graph.
In an undirected graph, a connected component is a subgraph in which any two vertices are connected to each other by paths, and which is connected to no additional vertices in the graph.
In simpler terms, a connected component is a group of vertices that are all reachable from each other.
Example:
Graph:
A -- B -- C
D -- E -- F
G
Connected components: [A, B, C], [D, E, F], [G]
Explanation: This graph has three connected components. The first component contains vertices A, B, and C, which are all reachable from each other. The second component contains D, E, and F. The third component contains only G, which is not connected to any other vertex.
BFS guarantees that all vertices reachable from a starting vertex will be visited. This makes it perfect for finding all vertices in a connected component.
BFS has a time complexity of O(V + E), which is optimal for traversing a graph. It visits each vertex and edge exactly once.
The algorithm for finding connected components using BFS is straightforward: run BFS from each unvisited vertex to find all vertices in its component.
Initialize a set to keep track of visited vertices and an array to store all connected components.
For each unvisited vertex in the graph, run BFS to find all vertices in its connected component.
During BFS, mark all visited vertices and add them to the current component. This ensures each vertex is part of exactly one component.
Here's an implementation of the connected components algorithm using BFS:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768function findConnectedComponents(graph) { // Set to keep track of visited vertices const visited = new Set(); // Array to store all connected components const components = []; // For each vertex in the graph for (const vertex in graph) { // If this vertex has not been visited yet if (!visited.has(vertex)) { // Find all vertices in the same component as this vertex const component = bfsComponent(graph, vertex, visited); // Add this component to the list of components components.push(component); } } return components;} function bfsComponent(graph, startVertex, visited) { // Queue for BFS const queue = [startVertex]; // Mark the start vertex as visited visited.add(startVertex); // Array to store vertices in this component const component = [startVertex]; // While there are vertices in the queue while (queue.length > 0) { // Dequeue a vertex from the queue const currentVertex = queue.shift(); // Get all adjacent vertices of the dequeued vertex for (const neighbor of graph[currentVertex]) { // If this adjacent vertex has not been visited if (!visited.has(neighbor)) { // Mark it as visited and enqueue it visited.add(neighbor); queue.push(neighbor); // Add it to this component component.push(neighbor); } } } return component;} // Example usage:const graph = { 'A': ['B'], 'B': ['A', 'C'], 'C': ['B'], 'D': ['E'], 'E': ['D', 'F'], 'F': ['E'], 'G': []}; const components = findConnectedComponents(graph);console.log(components);// Output: [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]
Key Insight: We run BFS from each unvisited vertex to find all vertices in its connected component. By marking vertices as visited, we ensure that each vertex is part of exactly one component.
O(V + E), where V is the number of vertices and E is the number of edges in the graph.
Explanation: We visit each vertex once (O(V)) and explore each edge once (O(E)). Even though we run BFS multiple times, each vertex and edge is processed exactly once across all BFS calls.
O(V), where V is the number of vertices in the graph.
Explanation: We need to store the visited set (O(V)) and the queue for BFS (O(V) in the worst case). Additionally, we need O(V) space for storing the components. Overall, the space complexity is O(V).
Counting the number of islands in a 2D grid, where each island is a connected component of land cells.
Finding the number of friend circles in a social network, where each circle is a connected component of friends.
Identifying connected regions in an image for image segmentation or object recognition.
A classic application of the connected components pattern is the Number of Islands problem, where we need to count the number of islands in a 2D grid. An island is a group of connected land cells (represented by '1'), surrounded by water cells (represented by '0').
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162function numIslands(grid) { if (!grid || grid.length === 0) { return 0; } const rows = grid.length; const cols = grid[0].length; let count = 0; // Directions: up, right, down, left const directions = [[-1, 0], [0, 1], [1, 0], [0, -1]]; // Function to check if a cell is valid and is land function isValid(row, col) { return row >= 0 && row < rows && col >= 0 && col < cols && grid[row][col] === '1'; } // BFS to mark all connected land cells as visited function bfs(row, col) { const queue = [[row, col]]; grid[row][col] = '0'; // Mark as visited by changing '1' to '0' while (queue.length > 0) { const [currentRow, currentCol] = queue.shift(); // Check all four directions for (const [dr, dc] of directions) { const newRow = currentRow + dr; const newCol = currentCol + dc; if (isValid(newRow, newCol)) { queue.push([newRow, newCol]); grid[newRow][newCol] = '0'; // Mark as visited } } } } // Iterate through each cell in the grid for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { // If we find a land cell, start BFS and increment count if (grid[i][j] === '1') { count++; bfs(i, j); } } } return count;} // Example usage:const grid = [ ['1', '1', '0', '0', '0'], ['1', '1', '0', '0', '0'], ['0', '0', '1', '0', '0'], ['0', '0', '0', '1', '1']]; const islands = numIslands(grid);console.log(islands); // Output: 3
How it works: We iterate through each cell in the grid. When we find a land cell ('1'), we start BFS from that cell to mark all connected land cells as visited (by changing them to '0'). Each time we start a new BFS, we've found a new island, so we increment our count.