The Shortest Path Pattern is a BFS application that finds the shortest path between two vertices in an unweighted graph.
BFS guarantees the shortest path in unweighted graphs because it explores vertices in order of their distance from the source.
Given an unweighted graph and two vertices, find the shortest path (the path with the fewest edges) between them.
Example:
Graph: A -- B -- D
| |
C -- F -- E
Start: A, End: F
Shortest path: A → C → F
Distance: 2 edges
Here's an implementation of the shortest path 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 shortest path pattern is the Word Ladder problem, where we need to transform one word into another by changing one letter at a time.
Learn how to use BFS to find the shortest path between two vertices in an unweighted graph.
The Shortest Path Pattern is a BFS application that finds the shortest path between two vertices in an unweighted graph.
BFS guarantees the shortest path in unweighted graphs because it explores vertices in order of their distance from the source. When a vertex is first discovered, the path to it must be the shortest possible.
Example:
Graph:
A -- B -- D
| |
C -- F -- E
Start: A, End: F
Shortest path: A → C → F
Distance: 2 edges
Explanation: BFS explores all vertices at distance 1 from A (B and C) before moving to vertices at distance 2. When it reaches F, it has found the shortest path.
BFS explores vertices in order of their distance from the source. It visits all vertices at distance 1, then all vertices at distance 2, and so on.
When a vertex is first discovered by BFS, the path to it must be the shortest possible. This is because BFS would have already explored all shorter paths.
This guarantee only holds for unweighted graphs or graphs where all edges have the same weight. For weighted graphs, Dijkstra's algorithm or other algorithms are needed.
Start at the source vertex, mark it as visited, and enqueue it along with its distance (0) and path so far.
Dequeue a vertex, check if it's the destination, and if not, explore all its unvisited neighbors.
For each neighbor, track its distance (parent's distance + 1) and the path to reach it (parent's path + neighbor).
Return the path and distance when the destination is found, or indicate no path exists if the queue becomes empty.
Here's an implementation of the shortest path algorithm using BFS:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455function shortestPath(graph, startVertex, endVertex) { // If start and end are the same, return an empty path if (startVertex === endVertex) { return { distance: 0, path: [startVertex] }; } // Set to keep track of visited vertices const visited = new Set(); // Queue for BFS, storing [vertex, distance, path] const queue = [[startVertex, 0, [startVertex]]]; // Mark the start vertex as visited visited.add(startVertex); // While there are vertices in the queue while (queue.length > 0) { // Dequeue a vertex from the queue const [currentVertex, distance, path] = queue.shift(); // Get all adjacent vertices of the dequeued vertex for (const neighbor of graph[currentVertex]) { // If this adjacent vertex is the destination, we've found the shortest path if (neighbor === endVertex) { return { distance: distance + 1, path: [...path, neighbor] }; } // If this adjacent vertex has not been visited, mark it as visited and enqueue it if (!visited.has(neighbor)) { visited.add(neighbor); queue.push([neighbor, distance + 1, [...path, neighbor]]); } } } // If we reach here, there is no path from start to end return { distance: -1, path: [] };} // Example usage:const graph = { 'A': ['B', 'C'], 'B': ['A', 'D', 'E'], 'C': ['A', 'F'], 'D': ['B'], 'E': ['B', 'F'], 'F': ['C', 'E']}; const result = shortestPath(graph, 'A', 'F');console.log("Shortest distance:", result.distance); // Output: 2console.log("Shortest path:", result.path); // Output: ['A', 'C', 'F']
Key Insight: This implementation not only finds the shortest distance but also reconstructs the actual path from the source to the destination. It does this by keeping track of the path so far for each vertex in the queue.
O(V + E), where V is the number of vertices and E is the number of edges in the graph.
Explanation: In the worst case, we visit each vertex once (O(V)) and explore each edge once (O(E)). For a connected graph, E is at least V-1, so the time complexity is dominated by the number of edges.
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 (O(V) in the worst case). Additionally, we need O(V) space for storing the path. Overall, the space complexity is O(V).
Finding the shortest path through a maze, where each cell is a vertex and adjacent cells are connected by edges.
Finding the shortest transformation sequence from one word to another, where each word is a vertex and words that differ by one letter are connected by edges.
Finding the shortest path for a knight to move from one position to another on a chessboard, where each position is a vertex and valid knight moves are edges.
A classic application of the shortest path pattern is the Word Ladder problem, where we need to transform one word into another by changing one letter at a time, with each intermediate word being a valid word from a given dictionary.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455function wordLadder(beginWord, endWord, wordList) { // If endWord is not in wordList, return 0 if (!wordList.includes(endWord)) { return 0; } // Convert wordList to a Set for O(1) lookups const wordSet = new Set(wordList); // Queue for BFS, storing [word, distance] const queue = [[beginWord, 1]]; // Set to keep track of visited words const visited = new Set([beginWord]); // While there are words in the queue while (queue.length > 0) { // Dequeue a word from the queue const [currentWord, distance] = queue.shift(); // If we've reached the end word, return the distance if (currentWord === endWord) { return distance; } // Try changing each character of the current word for (let i = 0; i < currentWord.length; i++) { // Try all possible characters for (let j = 0; j < 26; j++) { // Generate a new word by changing one character const newChar = String.fromCharCode(97 + j); // 'a' to 'z' const newWord = currentWord.slice(0, i) + newChar + currentWord.slice(i + 1); // If the new word is in the word list and hasn't been visited if (wordSet.has(newWord) && !visited.has(newWord)) { // Mark it as visited and enqueue it visited.add(newWord); queue.push([newWord, distance + 1]); } } } } // If we reach here, there is no transformation sequence return 0;} // Example usage:const beginWord = "hit";const endWord = "cog";const wordList = ["hot", "dot", "dog", "lot", "log", "cog"]; const result = wordLadder(beginWord, endWord, wordList);console.log("Shortest transformation sequence length:", result); // Output: 5// The transformation sequence is: "hit" -> "hot" -> "dot" -> "dog" -> "cog"
How it works: We model the problem as a graph where each word is a vertex, and there is an edge between two words if they differ by exactly one letter. We then use BFS to find the shortest path from the begin word to the end word.
The Shortest Path Pattern is a BFS application that finds the shortest path between two vertices in an unweighted graph.
BFS guarantees the shortest path in unweighted graphs because it explores vertices in order of their distance from the source.
Given an unweighted graph and two vertices, find the shortest path (the path with the fewest edges) between them.
Example:
Graph: A -- B -- D
| |
C -- F -- E
Start: A, End: F
Shortest path: A → C → F
Distance: 2 edges
Here's an implementation of the shortest path 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 shortest path pattern is the Word Ladder problem, where we need to transform one word into another by changing one letter at a time.
Learn how to use BFS to find the shortest path between two vertices in an unweighted graph.
The Shortest Path Pattern is a BFS application that finds the shortest path between two vertices in an unweighted graph.
BFS guarantees the shortest path in unweighted graphs because it explores vertices in order of their distance from the source. When a vertex is first discovered, the path to it must be the shortest possible.
Example:
Graph:
A -- B -- D
| |
C -- F -- E
Start: A, End: F
Shortest path: A → C → F
Distance: 2 edges
Explanation: BFS explores all vertices at distance 1 from A (B and C) before moving to vertices at distance 2. When it reaches F, it has found the shortest path.
BFS explores vertices in order of their distance from the source. It visits all vertices at distance 1, then all vertices at distance 2, and so on.
When a vertex is first discovered by BFS, the path to it must be the shortest possible. This is because BFS would have already explored all shorter paths.
This guarantee only holds for unweighted graphs or graphs where all edges have the same weight. For weighted graphs, Dijkstra's algorithm or other algorithms are needed.
Start at the source vertex, mark it as visited, and enqueue it along with its distance (0) and path so far.
Dequeue a vertex, check if it's the destination, and if not, explore all its unvisited neighbors.
For each neighbor, track its distance (parent's distance + 1) and the path to reach it (parent's path + neighbor).
Return the path and distance when the destination is found, or indicate no path exists if the queue becomes empty.
Here's an implementation of the shortest path algorithm using BFS:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455function shortestPath(graph, startVertex, endVertex) { // If start and end are the same, return an empty path if (startVertex === endVertex) { return { distance: 0, path: [startVertex] }; } // Set to keep track of visited vertices const visited = new Set(); // Queue for BFS, storing [vertex, distance, path] const queue = [[startVertex, 0, [startVertex]]]; // Mark the start vertex as visited visited.add(startVertex); // While there are vertices in the queue while (queue.length > 0) { // Dequeue a vertex from the queue const [currentVertex, distance, path] = queue.shift(); // Get all adjacent vertices of the dequeued vertex for (const neighbor of graph[currentVertex]) { // If this adjacent vertex is the destination, we've found the shortest path if (neighbor === endVertex) { return { distance: distance + 1, path: [...path, neighbor] }; } // If this adjacent vertex has not been visited, mark it as visited and enqueue it if (!visited.has(neighbor)) { visited.add(neighbor); queue.push([neighbor, distance + 1, [...path, neighbor]]); } } } // If we reach here, there is no path from start to end return { distance: -1, path: [] };} // Example usage:const graph = { 'A': ['B', 'C'], 'B': ['A', 'D', 'E'], 'C': ['A', 'F'], 'D': ['B'], 'E': ['B', 'F'], 'F': ['C', 'E']}; const result = shortestPath(graph, 'A', 'F');console.log("Shortest distance:", result.distance); // Output: 2console.log("Shortest path:", result.path); // Output: ['A', 'C', 'F']
Key Insight: This implementation not only finds the shortest distance but also reconstructs the actual path from the source to the destination. It does this by keeping track of the path so far for each vertex in the queue.
O(V + E), where V is the number of vertices and E is the number of edges in the graph.
Explanation: In the worst case, we visit each vertex once (O(V)) and explore each edge once (O(E)). For a connected graph, E is at least V-1, so the time complexity is dominated by the number of edges.
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 (O(V) in the worst case). Additionally, we need O(V) space for storing the path. Overall, the space complexity is O(V).
Finding the shortest path through a maze, where each cell is a vertex and adjacent cells are connected by edges.
Finding the shortest transformation sequence from one word to another, where each word is a vertex and words that differ by one letter are connected by edges.
Finding the shortest path for a knight to move from one position to another on a chessboard, where each position is a vertex and valid knight moves are edges.
A classic application of the shortest path pattern is the Word Ladder problem, where we need to transform one word into another by changing one letter at a time, with each intermediate word being a valid word from a given dictionary.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455function wordLadder(beginWord, endWord, wordList) { // If endWord is not in wordList, return 0 if (!wordList.includes(endWord)) { return 0; } // Convert wordList to a Set for O(1) lookups const wordSet = new Set(wordList); // Queue for BFS, storing [word, distance] const queue = [[beginWord, 1]]; // Set to keep track of visited words const visited = new Set([beginWord]); // While there are words in the queue while (queue.length > 0) { // Dequeue a word from the queue const [currentWord, distance] = queue.shift(); // If we've reached the end word, return the distance if (currentWord === endWord) { return distance; } // Try changing each character of the current word for (let i = 0; i < currentWord.length; i++) { // Try all possible characters for (let j = 0; j < 26; j++) { // Generate a new word by changing one character const newChar = String.fromCharCode(97 + j); // 'a' to 'z' const newWord = currentWord.slice(0, i) + newChar + currentWord.slice(i + 1); // If the new word is in the word list and hasn't been visited if (wordSet.has(newWord) && !visited.has(newWord)) { // Mark it as visited and enqueue it visited.add(newWord); queue.push([newWord, distance + 1]); } } } } // If we reach here, there is no transformation sequence return 0;} // Example usage:const beginWord = "hit";const endWord = "cog";const wordList = ["hot", "dot", "dog", "lot", "log", "cog"]; const result = wordLadder(beginWord, endWord, wordList);console.log("Shortest transformation sequence length:", result); // Output: 5// The transformation sequence is: "hit" -> "hot" -> "dot" -> "dog" -> "cog"
How it works: We model the problem as a graph where each word is a vertex, and there is an edge between two words if they differ by exactly one letter. We then use BFS to find the shortest path from the begin word to the end word.