101 Logo
onenoughtone

Shortest Path Pattern

What is the Shortest Path Pattern?

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.

Problem Statement

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

BFS Approach

  1. Start at the source vertex and mark it as visited
  2. Enqueue the source vertex into a queue, along with its distance (0) and path so far
  3. While the queue is not empty:
    • Dequeue a vertex, its distance, and path from the queue
    • If this vertex is the destination, return the distance and path
    • Otherwise, enqueue all unvisited neighbors with distance + 1 and updated path
  4. If the queue becomes empty without finding the destination, there is no path

Implementation

Here's an implementation of the shortest path algorithm using BFS:

function 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: 2 console.log("Shortest path:", result.path); // Output: ['A', 'C', 'F']

Time and Space Complexity

Time Complexity:

O(V + E), where V is the number of vertices and E is the number of edges in the graph.

Space Complexity:

O(V), where V is the number of vertices in the graph.

Related Problem: Word Ladder

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.

function 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"
IntroVisualizePatternsPractice
101 Logo
onenoughtone