Bipartite Graph Check in DSA Python - Time & Space Complexity
Checking if a graph is bipartite means verifying if we can split nodes into two groups without edges inside the same group.
We want to know how the time needed grows as the graph gets bigger.
Analyze the time complexity of the following code snippet.
from collections import deque
def is_bipartite(graph):
color = {}
for node in graph:
if node not in color:
queue = deque([node])
color[node] = 0
while queue:
current = queue.popleft()
for neighbor in graph[current]:
if neighbor not in color:
color[neighbor] = 1 - color[current]
queue.append(neighbor)
elif color[neighbor] == color[current]:
return False
return True
This code checks if a graph is bipartite by coloring nodes using breadth-first search.
- Primary operation: Visiting each node and its neighbors once using BFS.
- How many times: Each node and edge is processed at most once.
As the graph grows, the time to check grows roughly with the number of nodes plus edges.
| Input Size (n nodes, m edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 25 operations |
| 100 nodes, 200 edges | About 300 operations |
| 1000 nodes, 5000 edges | About 6000 operations |
Pattern observation: Operations grow roughly in a straight line with total nodes plus edges.
Time Complexity: O(n + m)
This means the time grows linearly with the number of nodes and edges in the graph.
[X] Wrong: "The algorithm checks every possible pair of nodes, so it must be O(n²)."
[OK] Correct: The algorithm only visits each edge once, not all pairs, so it runs faster than checking all pairs.
Understanding this time complexity helps you explain how graph algorithms scale and shows you can analyze BFS-based solutions clearly.
"What if the graph was represented as an adjacency matrix instead of adjacency lists? How would the time complexity change?"
Practice
bipartite?Solution
Step 1: Understand bipartite graph definition
A bipartite graph means its vertices can be split into two sets where no edge connects vertices within the same set.Step 2: Compare options with definition
Only Its vertices can be divided into two groups with no edges inside the same group matches this definition exactly. Other options describe different graph properties.Final Answer:
Its vertices can be divided into two groups with no edges inside the same group -> Option BQuick Check:
Bipartite = Two groups, no internal edges [OK]
- Confusing bipartite with equal vertices and edges
- Thinking bipartite means no cycles
- Assuming all vertices have same degree
Solution
Step 1: Identify adjacency list format
An adjacency list uses a dictionary mapping each vertex to a list of connected vertices.Step 2: Check each option
graph = {0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]} uses a dictionary with lists, correctly representing adjacency. graph = [[0, 1], [1, 2], [2, 3], [3, 0]] is a list of edges, not adjacency list. graph = {0: 1, 1: 2, 2: 3, 3: 0} maps to single vertex, not list. graph = [0, 1, 2, 3] is just a list of vertices.Final Answer:
graph = {0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]} -> Option CQuick Check:
Adjacency list = dict with lists [OK]
- Using list of edges instead of adjacency list
- Mapping vertex to single vertex instead of list
- Using just a list of vertices without edges
def is_bipartite(graph):
color = {}
def dfs(node, c):
if node in color:
return color[node] == c
color[node] = c
return all(dfs(nei, 1 - c) for nei in graph[node])
return all(dfs(node, 0) for node in graph if node not in color)
graph = {0: [1], 1: [0, 2], 2: [1, 3], 3: [2]}
print(is_bipartite(graph))Solution
Step 1: Understand DFS coloring logic
The function colors nodes 0 or 1 alternately. If a conflict occurs, it returns False.Step 2: Trace the graph coloring
Start at node 0 with color 0, node 1 gets color 1, node 2 color 0, node 3 color 1. No conflicts found.Final Answer:
True -> Option AQuick Check:
Graph is bipartite, so output is True [OK]
- Assuming graph with chain edges is not bipartite
- Confusing color assignment logic
- Ignoring disconnected nodes
def is_bipartite(graph):
color = {}
def dfs(node, c):
if node in color:
return color[node] != c
color[node] = c
return all(dfs(nei, 1 - c) for nei in graph[node])
return all(dfs(node, 0) for node in graph if node not in color)Solution
Step 1: Analyze the color check condition
The code returns False if a node is already colored with the same color c, so it should check equality to detect conflict.Step 2: Identify the incorrect operator
The code uses != which returns True if colors differ, which is wrong. It should be == to detect conflict and return False.Final Answer:
The condition should be color[node] == c, not != c -> Option DQuick Check:
Conflict check needs equality, not inequality [OK]
- Using != instead of == in color conflict check
- Changing color dict to list unnecessarily
- Ignoring return values in dfs
[(0,1), (1,2), (2,3), (3,0), (2,4)], which statement is true about its bipartite property?Solution
Step 1: Identify cycles in the graph
The edges form a cycle 0-1-2-3-0 which has 4 edges (even), so no odd cycle exists.Step 2: Check for odd cycles
Since the only cycle is even length, the graph is bipartite.Final Answer:
The graph is bipartite because it has no odd cycles -> Option AQuick Check:
Odd cycle means not bipartite; no odd cycle means bipartite [OK]
- Confusing even and odd cycle lengths
- Assuming disconnected means not bipartite
- Ignoring extra edges when checking cycles
Ready to prove it?
Pass the test and this pattern moves unknown
