Problem Statement

Given an undirected graph with V vertices labeled from 0 to V-1. The graph is represented using an adjacency list where adj[i] lists all nodes connected to node. Determine if the graph is bipartite or not.

A graph is bipartite if the nodes can be partitioned into two independent sets A and B such that every edge in the graph connects a node in set A and a node in set B.

Equivalent, a graph is bipartite if it is 2-colorable, you can color all vertices using two colors such that no two adjacent vertices share the same color.

Examples

Example 1:

Input: V = 4,
       adj = [
              [1, 3],
              [0, 2],
              [1, 3],
              [0, 2]
             ]
    0 --- 1
    |     |
    3 --- 2

Output: true

Explanation:
The given graph is bipartite since, we can partition the nodes into two sets: {0, 2} and {1, 3}.
Example 2:

Input: V = 3,
       adj = [
              [1, 2],
              [0, 2],
              [0, 1]
             ]
      0
     / \
    1---2

Output: false

Explanation:
No way to divide the vertices into two sets without edges within the same set. The graph is not bipartite.

Different Approaches

1️⃣ BFS

Intuition:

A bipartite graph is a graph that can be colored using 2 colors such that no adjacent nodes have the same color. Any linear graph with no cycle is always a bipartite graph. With a cycle, any graph with an even cycle length can also be a bipartite graph. So, any graph with an odd cycle length can never be a bipartite graph.

To check if the graph is bipartite, it can check if the nodes can be colored alternatingly. If alternate coloring of nodes is possible, the graph is bipartite, else not.

Approach:

  1. Initialize a color array with all nodes initially uncolored represented by -1. Green and Yellow colors will be represented as integer value 0 and 1 respectively.
  2. Start the BFS traversal from an unvisited node and perform the following steps:
    1. If a node is uncolored, color it with alternating colors.
    2. If a node is previously colored, check if it follows alternate colors. If not, the graph can be said as not bipartite.
  3. If all the nodes can be colored with alternating colors, the graph can be classified as bipartite.

Dry Run:

image-398.png
image-399.png
image-400.png
image-397.png

Code:

#include <bits/stdc++.h>
using namespace std;

class Solution {
private:
    
    /* Function to perform BFS traversal and color
    the nodes with alternate colors in a component */
    bool bfs(int start, int V, vector<int> adj[], int color[]) {
        // Queue for BFS traversal
        queue <int> q;
        
        // Add initial node to queue
        q.push(start);
        color[start] = 0; // Mark it with a color
        
        // While queue is not empty
        while(!q.empty()) {
            // Get the node
            int node = q.front();
            q.pop();
            
            // Traverse all its neighbors
            for(auto it : adj[node]) {
                
                // If not already colored
                if(color[it] == -1) {
                    
                    // Color it with opposite color.
                    color[it] = !color[node];
                    
                    // Push the node in queue
                    q.push(it);
                }
                
                // Else if the neighbor has same color as node
                else if(color[it] == color[node]) {
                    
                    /* Return false, as the 
                    component is not bipartite */
                    return false;
                }
            }
        }
        
        // Return true is the component is bipartite
        return true;
    }
    
    
public:
    /* Function to check if the 
    given graph is bipartite */
    bool isBipartite(int V, vector<int> adj[]) {
        
        /* To store the color of nodes, where 
        each node is uncolored initially */
        int color[V];
        for(int i=0; i < V; i++) color[i] = -1;
        
        // Traverse all the nodes 
        for(int i=0; i < V; i++) {
            
            // If not colored, start the traversal
            if(color[i] == -1) {
                // Return false if graph is not bipartite
                if(!bfs(i, V, adj, color))
                    return false;
            }
        }
        
        /* Return true if each 
        component is bipartite */
        return true;
    }
};

int main() {
    
    int V = 4;
    vector<int> adj[V] = {
        {1,3},
        {0,2},
        {1,3},
        {0,2}
    };
    
    /* Creating an instance of 
    Solution class */
    Solution sol; 
    
    /* Function call to check 
    if the given graph is bipartite */
    bool ans = sol.isBipartite(V, adj);
    
    // Output
    if(ans) 
        cout << "The given graph is a bipartite graph.";
    else 
        cout << "The given graph is not a bipartite graph.";
    
    return 0;
}

Complexity Analysis:

  • Time Complexity: O(V+E) (where V is the number of nodes and E is the number of edges in the graph)
    The BFS Traversal takes O(V+E) time.
  • Space Complexity: O(V)
    The color array takes O(V) space and queue space for BFS is O(V) for the worst case.

2️⃣ DFS

Intuition:

A bipartite graph is a graph that can be colored using 2 colors such that no adjacent nodes have the same color. Any linear graph with no cycle is always a bipartite graph. With a cycle, any graph with an even cycle length can also be a bipartite graph. So, any graph with an odd cycle length can never be a bipartite graph.

In order to check if the given graph is bipartite, it can checked if the nodes can be colors alternatingly. If alternate coloring of nodes is possible, the graph is bipartite, else not.

Approach:

  1. Initialize a color array with all nodes initially uncolored represented by -1. Green and Yellow colors will be represented as integer value 0 and 1 respectively.
  2. Start the DFS traversal from the node and perform the following steps:
    1. If a node is uncolored, color it with alternating colors.
    2. If a node is previously colored, check if it follows alternate colors. If not, the graph can be said as not bipartite.
    3. If all the nodes can be colored with alternating colors, the graph can be classified as bipartite.

Dry Run:

image-401.png
image-402.png
image-403.png
image-404.png
image-405.png
image-406.png
image-407.png
image-408.png
image-409.png
image-410.png

Code:

#include <bits/stdc++.h>
using namespace std;

class Solution {
private:

    /* Function to perform DFS traversal and 
    color the nodes with alternate colors*/
    bool dfs(int node, int col, vector<int> &color, 
             vector<int> adj[]) {
        
        // Color the current node
        color[node] = col; 
        
        // Traverse adjacent nodes
        for(auto it : adj[node]) {
            
            // if uncoloured
            if(color[it] == -1) {
                
                // Recursively color the nodes 
                if(dfs(it, !col, color, adj) == false) 
                    return false; 
            }
            
            // if previously coloured and have the same colour
            else if(color[it] == col) {
                
                // Return false as it is not bipartite
                return false; 
            }
        }
        
        /* Return true if all the nodes can 
        be colored with alternate colors */
        return true; 
    }

public:
    /* Function to check if the 
    given graph is bipartite */
    bool isBipartite(int V, vector<int> adj[]) {
        
        /* To store the color of nodes, where 
        each node is uncolored initially */
        vector<int> color(V, -1);
        
        // Start Traversal of connected components
        for(int i=0; i<V; i++) {
            
            /* if a node is not colored, 
            a new component is found */
            if(color[i] == -1) {
                
                /* Start DFS traversal 
                and color each node */
                if(dfs(i, 0, color, adj) == false) {
                    
                    /* Return false if component 
                    is found not to be bipartite */
                    return false;
                }
            }
        }
        
        /* Return true if each 
        component is bipartite */
        return true;
    }
};

int main() {
    
    int V = 4;
    vector<int> adj[V] = {
        {1,3},
        {0,2},
        {1,3},
        {0,2}
    };
    
    /* Creating an instance of 
    Solution class */
    Solution sol; 
    
    /* Function call to check 
    if the given graph is bipartite */
    bool ans = sol.isBipartite(V, adj);
    
    // Output
    if(ans) 
        cout << "The given graph is a bipartite graph.";
    else 
        cout << "The given graph is not a bipartite graph.";
    
    return 0;
}

Complexity Analysis:

  • Time Complexity: O(V+E) (where V is the number of nodes and E is the number of edges in the graph.)
    The DFS Traversal takes O(V+E) time.
  • Space Complexity: O(V)
    • The color array takes O(V) space and recursion stack space for DFS is O(V) for the worst case.