Create your own
Lesson illustration

Graph Problem Solving Techniques

Welcome back! In our last lesson, we developed a method for tackling linked list and tree problems by focusing on the "state" required at each step of a traversal. This systematic approach of identifying the crucial information needed to make decisions is a powerful tool for moving from a problem statement to a concrete algorithm.

Today, we'll apply that same structured thinking to graph problems. You've already learned the mechanics of key graph algorithms like BFS, DFS, Dijkstra's, and topological sort. This lesson shifts the focus from how these algorithms work to when and why you should choose one over the other. Our goal is to equip you with a mental checklist that allows you to confidently deconstruct an unseen Medium-level graph problem, model it correctly, and select the most appropriate algorithm from your toolbox.

A Quick Refresher on Graph Concepts

Before we build our decision framework, let's have a quick, high-energy refresher on the fundamental concepts of graphs and the main traversal strategies. The following video from Fireship provides an excellent overview.

Graph Search Algorithms in 100 Seconds - And Beyond with JS

Watch this short video, "Graph Search Algorithms in 100 Seconds," for a rapid review of core ideas.

Focus on these key segments: Graph Terminology: Recap nodes, edges, and directed vs. undirected graphs. Representations: Understand the trade-offs between an adjacency matrix and an adjacency list. As you know from your front-end work, choosing the right data structure is half the battle. Traversal Basics: Note the conceptual difference between the "deep" exploration of DFS and the "wide" exploration of BFS.

The Three-Step Framework for Graph Problems

Facing a new graph problem can feel overwhelming due to the variety of possible approaches. The key to cutting through this complexity is a repeatable, three-step process. This structured approach helps transform ambiguity into a clear plan of action, which is invaluable for managing the "algo phobia" you've mentioned.

Here is the framework:

  1. Identify the Graph Model: First, translate the problem's components into graph terminology.

    • Nodes: What entities are being represented? (e.g., cities, people, courses, grid cells).
    • Edges: What are the relationships between them? (e.g., roads, friendships, prerequisites, adjacency).
    • Direction: Are the relationships one-way (directed) or two-way (undirected)?
    • Weights: Do the connections have a cost, distance, or time associated with them? If so, the graph is weighted. If not, all edges can be considered to have a weight of 1.
  2. Choose the Right Tool: Next, analyze the core question being asked. Certain keywords and problem structures are strong signals for specific algorithms.

If the problem asks for...The primary tool is likely...Because...
Shortest path, fewest steps, minimum moves (unweighted)Breadth-First Search (BFS)BFS explores layer by layer, guaranteeing it finds the shortest path in terms of the number of edges.
Shortest path, minimum cost, cheapest route (weighted)Dijkstra's AlgorithmDijkstra's is a modified BFS that uses a priority queue to always explore the cheapest path discovered so far.
Prerequisites, dependencies, task ordering, course scheduleTopological SortThis algorithm specifically produces a linear ordering of nodes that respects all directed dependencies.
Path existence, reachability, connected components, "find all..."Depth-First Search (DFS) or BFSDFS is often more natural for exhaustive exploration and backtracking, while BFS also works for reachability.
Cycle detectionDFS (with node states) or Topological Sort (for DAGs)DFS can track a node's visitation state (visiting vs. visited) to find back edges. A failed topological sort also implies a cycle.
  1. Talk Through Edge Cases: Before you code, consider what could go wrong.
    • Disconnected Graph: What if not all nodes are reachable from the start? Your solution should handle this.
    • Cycles: How does your chosen algorithm behave if a cycle exists? This is critical for topological sort.
    • Negative Weights: Dijkstra's algorithm fails with negative edge weights. While rare in interviews, acknowledging this limitation shows depth.

To solidify this framework, let's read a guide that explicitly links these patterns to interview scenarios.

Graph Interview Questions: BFS, DFS, Dijkstra, Toposort & ...

This article from ShadeCoder provides excellent intuition on when to use each major graph algorithm. It's less about code and more about the strategic decision-making process we're focusing on.

Please read the following sections: Start with BFS and DFS. Pay close attention to the comparison table and the types of interview questions each is suited for. Next, read the section on Dijkstra’s Algorithm. The key takeaway here is understanding why a simple BFS fails on weighted graphs and how a priority queue solves this. Then, review the section on Topological Sort. Focus on the keywords that signal a toposort problem, like "prerequisites" and "dependencies." Finally, read the step-by-step guide at the end. This summarizes the mental checklist we're building today. You can skip the part about Union-Find for now; we'll cover that in a future module.

Applying the Framework: Worked Examples

Let's put this framework into practice with two classic Medium-level problems.

Example 1: Dependencies and Ordering (LeetCode 207. Course Schedule)

Problem: You are given numCourses and a list of prerequisites, where [a, b] means you must take course b before course a. Is it possible to finish all courses?

Let's apply our framework:

  1. Identify the Graph Model:

    • Nodes: The courses (0 to numCourses - 1).
    • Edges: The prerequisites. A prerequisite [a, b] represents a directed edge from b to a (b -> a), signifying that b must precede a.
    • Weights: There are no weights.
  2. Choose the Right Tool:

    • The keywords are "prerequisites" and the question is about "possibility to finish," which implies a valid ordering. This is a textbook signal for Topological Sort. An impossible schedule means there's a circular dependency (e.g., Course A needs B, and B needs A), which is a cycle in our directed graph.
  3. Algorithm and Edge Cases:

    • The goal is to detect if a cycle exists. We can do this using Kahn's algorithm (a BFS-based topological sort). We count the "in-degrees" (number of prerequisites) for each course. We start with courses that have an in-degree of 0. As we "take" a course, we decrement the in-degree of all courses that depend on it. If any of their in-degrees become 0, they are added to our queue of courses to take.
    • If we successfully process all numCourses, no cycle exists. If the process finishes but some courses were not processed, it means they are part of a cycle.
This image illustrates a topological sort on a Directed Acyclic Graph (DAG). The algorithm produces a linear ordering of nodes (BEACDFG) where for every directed edge from node u to node v, u comes before v in the ordering. This is exactly what's needed for a course schedule.

Now, let's dive into a detailed explanation and implementation.

207. Course Schedule - In-Depth Explanation

The Algo.monster guide for "Course Schedule" provides a fantastic, step-by-step breakdown of this exact problem, reinforcing our framework.

As you read, focus on these parts: How We Pick the Algorithm & Intuition: This section validates our decision to model this as a graph problem and use topological sort for cycle detection. Solution Approach and Example Walkthrough: Trace the example with numCourses = 4 to see Kahn's algorithm in action. See how the inDegree counts and the queue evolve. Solution Implementation: Review the TypeScript code. Notice how it directly maps to the logic of building the graph, calculating in-degrees, and processing the queue.

Example 2: Shortest Path with Costs (LeetCode 743. Network Delay Time)

Problem: You are given a network of n nodes, a list of travel times as directed edges [u, v, w], and a starting node k. Find the minimum time it takes for a signal to travel from k to all n nodes. If it's impossible for the signal to reach every node, return -1.

  1. Identify the Graph Model:

    • Nodes: The n network devices.
    • Edges: The connections [u, v, w], representing a directed edge from u to v with a weight of w.
    • Weights: Yes, the travel time w.
  2. Choose the Right Tool:

    • The problem asks for the "minimum time" for a signal to reach every node. This means we need the shortest path from the source k to all other nodes. Since the edges are weighted, simple BFS is not sufficient. This is the classic use case for Dijkstra's Algorithm. The final answer will be the maximum of all these shortest path distances.
  3. Algorithm and Edge Cases:

    • We'll use Dijkstra's, which maintains a priority queue of (cost, node) tuples, always processing the node that is cheapest to reach next. We also need a way to track the final shortest distance to each node and a set of visited nodes to avoid cycles and redundant work.
    • The main edge case is a disconnected graph. If, after the algorithm finishes, we haven't visited all n nodes, it's impossible to reach everyone, so we should return -1.
This diagram shows how Dijkstra's algorithm uses a priority queue (min-heap) to find the shortest paths from a start node (0). It always expands from the node with the current minimum distance, gradually "finalizing" the shortest path to each node.

The following video provides a clear, visual walkthrough of this problem using Dijkstra's algorithm.

Network Delay Time - Dijkstra's algorithm - Leetcode 743

Watch this NeetCode video on "Network Delay Time" to see how Dijkstra's algorithm solves this problem.

Focus on these segments: Problem Breakdown: Understand how the problem statement translates to finding the longest of all the shortest paths from a source. Dijkstra's Algorithm Explained: Pay close attention to the step-by-step example. Notice why the min-heap is essential for correctly choosing the next node to visit when paths have different costs. This is the core intuition. Code Walkthrough: Follow the Python implementation. The logic is directly transferable to TypeScript: build an adjacency list, initialize a min-heap and a visited set, and then loop while the heap is not empty, processing neighbors and updating costs.

Key Takeaways

  • Solving graph problems systematically starts with a three-step framework: model the graph, choose the right algorithm based on the core question, and consider edge cases.
  • Problem keywords are your guide:
    • "Shortest/fewest" + unweighted edges → BFS.
    • "Shortest/cheapest" + weighted edges → Dijkstra's.
    • "Prerequisites/dependencies/order" → Topological Sort.
    • "Connectivity/reachability/find all" → DFS (or BFS).
  • Always be prepared to justify your choice of algorithm. Explaining why you chose Dijkstra's over BFS, for example, is a strong signal in an interview.

In our next module, we'll venture into new algorithmic territory, starting with Greedy Decisions. You'll learn how making a locally optimal choice at each step can lead to a globally optimal solution for certain classes of problems, particularly those involving intervals and resource allocation.

Can't find a good explanation? Sign up and we'll make it for you

Sign up