101 Logo
onenoughtone

Bipartite Graph Pattern

What is a Bipartite Graph?

A bipartite graph is a graph whose vertices can be divided into two disjoint sets such that every edge connects a vertex in the first set to a vertex in the second set.

In other words, a graph is bipartite if its vertices can be colored using two colors such that no adjacent vertices have the same color.

Problem Statement

Given an undirected graph, determine if it is bipartite.

Example 1:

Graph: 0 -- 1 -- 2 -- 3 -- 0

Is bipartite: true
(Color 0 and 2 with one color, 1 and 3 with another color)

Example 2:

Graph: 0 -- 1 -- 2 -- 0

Is bipartite: false
(Cannot color the vertices with two colors)

BFS Approach

  1. Initialize a colors array with all vertices uncolored (-1)
  2. For each uncolored vertex in the graph:
    • Start BFS from this vertex and color it with color 0
    • For each neighbor, color it with the opposite color of its parent
    • If a neighbor is already colored with the same color as its parent, the graph is not bipartite
  3. If all vertices can be colored properly, the graph is bipartite

Implementation

Here's an implementation of the bipartite graph checking algorithm using BFS:

function isBipartite(graph) { const n = graph.length; // Initialize colors array with -1 (uncolored) const colors = Array(n).fill(-1); // Try to color the graph starting from each uncolored vertex for (let i = 0; i < n; i++) { // If this vertex is uncolored and we can't color it properly if (colors[i] === -1 && !bfsColorGraph(graph, i, colors)) { return false; } } // If we can color all vertices properly, the graph is bipartite return true; } function bfsColorGraph(graph, start, colors) { // Queue for BFS const queue = [start]; // Color the start vertex with color 0 colors[start] = 0; // While there are vertices in the queue while (queue.length > 0) { // Dequeue a vertex from the queue const current = queue.shift(); // Get all adjacent vertices of the dequeued vertex for (const neighbor of graph[current]) { // If this adjacent vertex is uncolored if (colors[neighbor] === -1) { // Color it with the opposite color of the current vertex colors[neighbor] = 1 - colors[current]; queue.push(neighbor); } // If this adjacent vertex is already colored with the same color as the current vertex else if (colors[neighbor] === colors[current]) { // The graph is not bipartite return false; } } } // If we can color all vertices properly, this component is bipartite return true; } // Example usage: const graph1 = [ [1, 3], // Vertex 0 is connected to vertices 1 and 3 [0, 2], // Vertex 1 is connected to vertices 0 and 2 [1, 3], // Vertex 2 is connected to vertices 1 and 3 [0, 2] // Vertex 3 is connected to vertices 0 and 2 ]; const graph2 = [ [1, 2, 3], // Vertex 0 is connected to vertices 1, 2, and 3 [0, 2], // Vertex 1 is connected to vertices 0 and 2 [0, 1, 3], // Vertex 2 is connected to vertices 0, 1, and 3 [0, 2] // Vertex 3 is connected to vertices 0 and 2 ]; console.log(isBipartite(graph1)); // Output: true console.log(isBipartite(graph2)); // Output: false

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: Possible Bipartition

A related problem is the Possible Bipartition problem, where we need to determine if we can divide a group of people into two groups such that no two people who dislike each other are in the same group.

function possibleBipartition(n, dislikes) { // Build the graph const graph = Array(n + 1).fill().map(() => []); for (const [a, b] of dislikes) { graph[a].push(b); graph[b].push(a); } // Initialize colors array with -1 (uncolored) const colors = Array(n + 1).fill(-1); // Try to color the graph starting from each uncolored vertex for (let i = 1; i <= n; i++) { // If this vertex is uncolored and we can't color it properly if (colors[i] === -1 && !bfsColorGraph(graph, i, colors)) { return false; } } // If we can color all vertices properly, the graph is bipartite return true; } function bfsColorGraph(graph, start, colors) { // Queue for BFS const queue = [start]; // Color the start vertex with color 0 colors[start] = 0; // While there are vertices in the queue while (queue.length > 0) { // Dequeue a vertex from the queue const current = queue.shift(); // Get all adjacent vertices of the dequeued vertex for (const neighbor of graph[current]) { // If this adjacent vertex is uncolored if (colors[neighbor] === -1) { // Color it with the opposite color of the current vertex colors[neighbor] = 1 - colors[current]; queue.push(neighbor); } // If this adjacent vertex is already colored with the same color as the current vertex else if (colors[neighbor] === colors[current]) { // The graph is not bipartite return false; } } } // If we can color all vertices properly, this component is bipartite return true; } // Example usage: const n = 4; const dislikes = [[1, 2], [1, 3], [2, 4], [3, 4]]; console.log(possibleBipartition(n, dislikes)); // Output: true
IntroVisualizePatternsPractice
101 Logo
onenoughtone