AlgoMaster Logo

Bipartite Graph Detection

Medium Priority13 min readUpdated May 30, 2026
Listen to this chapter
Unlock Audio

A graph is bipartite if its vertices can be split into two disjoint sets such that every edge connects a vertex in one set to a vertex in the other. Equivalently, the graph can be colored with two colors so that no edge has both endpoints in the same color.

This chapter covers what makes a graph bipartite, why bipartiteness fails exactly when an odd-length cycle exists, and three algorithms to detect it: BFS coloring, DFS coloring, and Union-Find.

What Is a Bipartite Graph?

A graph is bipartite if you can divide its vertices into two disjoint sets, say Set A and Set B, such that every edge connects a vertex in Set A to a vertex in Set B. No edge connects two vertices within the same set.

This is equivalent to saying the graph is 2-colorable: you can assign one of two colors to every vertex so that no two adjacent vertices share the same color.

There is a third way to characterize it. A graph is bipartite if and only if it contains no odd-length cycle. A cycle of length 3 (triangle), 5, 7, or any odd number makes 2-coloring impossible. Even-length cycles are fine.

Why does an odd cycle break things? Consider a cycle with 3 nodes: A-B-C-A. Color A with 0. Then B must be 1 (it is adjacent to A). Then C must be 0 (it is adjacent to B). But C is also adjacent to A, and both are color 0, which contradicts the coloring rule. The same logic extends to any odd-length cycle.

The diagram below shows a bipartite graph on the left and a non-bipartite graph on the right. The triangle in the non-bipartite graph makes a valid 2-coloring impossible.

In the bipartite graph, nodes A, B, C form one set (teal) and D, E, F form the other (orange). Every edge crosses between the two sets. In the non-bipartite graph, the triangle X-Y-Z makes 2-coloring impossible. No matter how you assign two colors, two adjacent nodes in that triangle will end up with the same color.

Real-World Applications

  • Job assignment: Given a set of workers and a set of tasks, with edges indicating which workers can do which tasks, the resulting graph is bipartite. Algorithms like the Hungarian method and Hopcroft-Karp build on this bipartite structure to find optimal assignments.
  • Course scheduling: Students and time slots form two sets. Conflicts (a student enrolled in two courses) create constraints. Checking if valid scheduling is possible often reduces to bipartite analysis.
  • Social network analysis: In a network where users interact, determining if the community can be divided into two non-overlapping groups (say, buyers and sellers on a marketplace) is a bipartiteness check.
  • Network flow: Many maximum flow and matching algorithms operate on bipartite graphs. The classic maximum bipartite matching problem is a direct application.
  • Recommendation systems: User-item interaction graphs are naturally bipartite (users on one side, items on the other), and algorithms exploit this structure for collaborative filtering.

The Core Idea

The Problem

Given an undirected graph, determine whether it is bipartite: can you assign one of two labels (say 0 and 1) to every vertex so that no edge connects two vertices with the same label?

A brute-force approach would try all possible 2-colorings. With n vertices, there are 2^n possible assignments. For each assignment, you would check if every edge connects differently colored vertices. That is exponential and far too slow.

The Key Insight

You do not need to try all colorings. You can determine the correct coloring greedily using BFS or DFS.

Pick any unvisited node and assign it color 0. Every neighbor of that node must be color 1 (there is no other valid choice). Every neighbor of those neighbors must be color 0, and so on. The coloring is forced at every step, with no decision to make.

If, during this forced coloring, you find a neighbor that has already been colored and its color matches the current node's color, you have found a conflict. That conflict means the graph is not bipartite, and there is guaranteed to be an odd-length cycle passing through those two nodes.

Visual Overview

The algorithm is a minor extension of standard BFS or DFS. Instead of tracking only "visited or not," you track the color assigned to each node. The rest of the traversal logic stays the same.

Approach 1: BFS

The BFS-based approach is a common one in interviews. Use a color array of size V filled with -1 (uncolored) that doubles as the visited marker. For each uncolored node, BFS outwards: color the source 0, assign every newly discovered neighbor the opposite color of the current node, and return false the moment a neighbor that is already colored matches the current node's color.

The outer loop over all nodes handles disconnected components, which is critical since a graph can be bipartite overall even if it has multiple disconnected parts.

Example Walkthrough

Let us trace through two examples to see the algorithm in action.

Example 1: A Bipartite Graph

Consider this graph with 6 nodes:

This forms a path-like structure: 0-1-2-3-4-5 with an extra edge 0-3.

Here is the BFS trace starting from node 0:

Every edge connects a teal node (color 0) to an orange node (color 1). The 2-coloring is valid.

Example 2: A Non-Bipartite Graph

Now consider a graph with a triangle:

Nodes 0, 1, 2 form a triangle (odd cycle of length 3).

The conflict happens at step 3 when we discover that node 2 (already colored 1) is a neighbor of node 1 (also colored 1). Both got the same color because they are both neighbors of node 0, but they are also neighbors of each other. This is the triangle 0-1-2, an odd cycle, and it makes 2-coloring impossible.

Implementation

The primary implementation uses BFS with a color array. The color array stores -1 for uncolored nodes, 0 for one color, and 1 for the other. The outer loop ensures all connected components are checked.

Code Explanation

The code follows the algorithm described earlier:

  1. The color array does triple duty. It tracks whether a node is visited (value != -1), which set/color it belongs to (0 or 1), and serves as the final partition if the graph turns out to be bipartite. This is cleaner than maintaining separate visited and color arrays.
  2. The 1 - color[node] trick. This flips between 0 and 1. If the current node is color 0, the neighbor gets color 1, and vice versa. It is a concise way to express "opposite color."
  3. The outer for loop. This is required for disconnected graphs. Without it, you would only check the component containing node 0 and miss conflicts in other components.
  4. The adjacency list representation. The input graph[i] is a list of neighbors of node i. This matches the format used by LeetCode 785 ("Is Graph Bipartite?").

Common Mistakes:

  • Forgetting the outer loop for disconnected components. If you only start BFS from node 0, disconnected non-bipartite components go undetected.
  • Using a boolean visited array instead of a color array. You need three states (unvisited, color 0, color 1), not two (visited, unvisited).
  • Checking the conflict condition incorrectly. The conflict is color[neighbor] == color[node], not color[neighbor] != -1. A neighbor being colored is fine as long as the colors differ.

Complexity Analysis

Time Complexity

Overall: O(V + E)

The analysis is identical to standard BFS:

  • Each vertex is enqueued and dequeued exactly once across the entire algorithm. This contributes O(V).
  • For each vertex, we iterate over its adjacency list. Summing across all vertices, this is O(E) for an undirected graph (each edge is examined twice, once from each endpoint, but this is still O(E)).
  • The outer loop iterates over all V vertices, but the inner BFS only processes vertices that have not been colored yet. So the total work across all BFS calls is O(V + E), not O(V * (V + E)).

Space Complexity

Overall: O(V)

  • The color array takes O(V) space.
  • The BFS queue can hold at most O(V) nodes in the worst case (for example, a star graph where all nodes are neighbors of the center).
  • No additional data structures are needed.

Variations and Extensions

Variation 1: DFS-Based Detection

The DFS approach uses recursion instead of a queue. It is functionally equivalent but sometimes more concise to write on a whiteboard.

The logic mirrors BFS exactly. The only difference is traversal order: DFS colors one branch completely before moving to the next, while BFS colors level by level.

Variation 2: Union-Find Approach

Union-Find offers an alternative perspective. The idea is: for each node, all its neighbors must belong to the opposite group. So all neighbors of a node should be in the same group as each other.

For each node u, union all neighbors of u together. Then check if u and any of its neighbors ended up in the same group. If they did, the graph is not bipartite.

This approach has a time complexity of O(V + E * alpha(V)), where alpha is the inverse Ackermann function (effectively constant). It is slightly less intuitive than BFS coloring but can be useful if you are already using Union-Find for other parts of the problem.

Variation 3: k-Colorability

Bipartite checking is the k=2 case of graph coloring. A natural question is: what about 3-colorable, 4-colorable, etc.? Unfortunately, determining if a graph is k-colorable for k >= 3 is NP-complete. There is no known polynomial-time algorithm. This makes the k=2 case special, and it is one of the few graph coloring problems that can be solved efficiently.

Comparison Table

ApproachTime ComplexitySpace ComplexityBest For
BFS ColoringO(V + E)O(V)Interviews, iterative preference
DFS ColoringO(V + E)O(V)Quick whiteboard, recursive preference
Union-FindO(V + E * alpha(V))O(V)When Union-Find is already in use
AlgorithmPurposeTimeSpaceKey Difference
BFS 2-ColoringBipartite detectionO(V + E)O(V)Colors nodes with 2 colors during traversal
DFS 2-ColoringBipartite detectionO(V + E)O(V)Same result, different traversal order
Union-FindBipartite detectionO(V + E * alpha(V))O(V)Groups neighbors, checks for conflicts
DFS Cycle DetectionFind any cycleO(V + E)O(V)Detects cycles but does not check parity
Graph Coloring (k >= 3)k-colorabilityNP-complete-No efficient algorithm known for k >= 3

When to Choose BFS 2-Coloring

  • You need a straightforward, iterative solution.
  • The graph might be very deep (avoiding recursion stack overflow).
  • You want to track the level or distance of each node as a bonus.

When NOT to Use BFS 2-Coloring

  • The problem asks for k-coloring with k >= 3 (NP-complete, different problem entirely).
  • You are already maintaining a Union-Find structure and want to avoid adding BFS on top.
  • The graph is represented as an edge list and converting to adjacency list is expensive (though this is rare in practice).

Common Patterns and Applications

Pattern 1: Partition Into Two Groups

Problem type: "Can we divide n elements into two groups such that no two elements in the same group have a conflict?"

How bipartite detection helps: Model elements as nodes, conflicts as edges. Run bipartite check. If the graph is bipartite, the two color classes give you the partition. If not, no valid partition exists.

Example: LeetCode 886 "Possible Bipartition" asks exactly this. Given n people and a list of pairs who dislike each other, can you split them into two groups so no one is in the same group as someone they dislike?

Pattern 2: Conflict Resolution

Problem type: "Assign one of two labels to each node respecting edge constraints."

How bipartite detection helps: This is literally 2-coloring. Any problem that asks you to assign binary labels (true/false, 0/1, team A/team B) to nodes with pairwise constraints is a bipartite check in disguise.

Pattern 3: Foundation for Matching

Problem type: Maximum matching, minimum vertex cover, or assignment problems on bipartite graphs.

How bipartite detection helps: Many matching algorithms (Hopcroft-Karp, Hungarian method) require the input graph to be bipartite. The first step is often verifying bipartiteness. Once confirmed, you can apply specialized bipartite matching algorithms that are more efficient than general matching algorithms.

Key Takeaways

  • A graph is bipartite when you can split its vertices into two disjoint sets so that every edge connects a vertex in one set to a vertex in the other, which is the same as saying the graph is 2-colorable.
  • A graph is bipartite if and only if it contains no odd-length cycle, so any triangle or other odd cycle makes a valid 2-coloring impossible.
  • Detection works by 2-coloring with BFS or DFS: color a starting node 0, assign every neighbor the opposite color, and report failure the moment a neighbor already carries the same color as the current node.
  • Both the BFS and DFS approaches run in O(V + E) time and O(V) space, and a color array using -1, 0, and 1 tracks the visited state and the assigned color at the same time.
  • The outer loop over all vertices is required so that every connected component is checked, since a graph can be bipartite overall while a separate disconnected component is not.
  • Union-Find offers an alternative that unions all neighbors of each node and then checks whether a node shares a group with any of its neighbors, running in O(V + E * alpha(V)) time.

Quiz

Bipartite Graph Detection Quiz

10 quizzes