Is Graph Bipartite?
Run a breadth-first search from each node that has no colour yet. Give the start colour 0. Every neighbour without a colour gets the opposite colour. If a neighbour already has the same colour as the node being popped, the answer is false. The outer loop covers every piece of the graph.
Every edge joins two nodes with different colours. Each edge is checked when its first end is popped, and by then both ends have colours.
Problem
You are given an undirected graph as an adjacency list. graph[u] lists every node that node u is joined to by an edge.
Can the nodes be split into two groups so that every edge joins a node in one group to a node in the other? Nodes inside one group may not be joined to each other.
Return true if such a split exists, otherwise false. The graph may have several separate pieces, and a node may have no edges at all.
graph, an adjacency list of n nodes numbered 0 to n − 1.
true if the nodes can be split into two groups with no edge inside a group, otherwise false.
Nodes 0, 1 and 2 are all joined to each other, a triangle. Each pair in the triangle must be in different groups, but with only two groups one pair always shares a group.
Put nodes 0 and 2 in one group and nodes 1 and 3 in the other. Every edge joins the two groups.
- • graph.length = n
- • 1 ≤ n ≤ 100
- • 0 ≤ graph[u].length < n
- • 0 ≤ graph[u][i] ≤ n − 1
- • graph[u] does not contain u
- • All the values in graph[u] are unique
- • If graph[u] contains v, then graph[v] contains u
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
What does an edge tell me about two nodes: must they be in the same group, or in different groups?
- 2.
If I give one node a group, which groups are forced on its neighbours?
- 3.
What goes wrong if I only look at the piece that contains node 0?
- 4.
How does a clash show up: between a node and a neighbour that already has a group?
- 5.
With n nodes and two groups, how many splits are there to try?
Brute force approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Try all 2^n colourings; accept the first one where no edge has equal colours | O(2^N · (N + E)) | O(1) |
| Optimal | Colour a node, give its neighbours the other colour; start a new BFS for each uncoloured node | O(N + E) | O(N) |
Why does this belong to this pattern?
- “split the nodes into two groups”Two groups are two colours: a 2-colouring.
- “every edge joins a node in one group to a node in the other”A rule on every edge: its two ends must get different colours.
- “several separate pieces, nodes with no edges”Start a new BFS in every piece, not only the one that holds node 0.
Colour one node and the rest of its piece is forced. That turns the check into a BFS: colour as you go, and a clash on any edge means false. This is the anchor of the Bipartite sub-pattern. The next question uses the same check, after building the graph from a list of pairs.
Don't make this mistake
On [[1],[0],[3,4],[2,4],[2,3]] (an edge 0–1 and a triangle 2–3–4), a BFS from node 0 alone colours 0 and 1, finds no clash, and returns true. The triangle is never looked at. The correct answer is false.
On the triangle [[1,2],[0,2],[0,1]], popping 0 colours nodes 1 and 2 with colour B. Popping 1 finds node 2 already coloured B, the same colour as 1, but the wrong version does not look at it. Popping 2 checks nothing, because its neighbour 1 is skipped the same way. It returns true, but a triangle cannot be split.
1 << n is undefined for n of 31 or more, and 2^100 colourings would never finish. The mask loop only works for small graphs, which is why it is the brute force and not the answer.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like Graph BFS / DFS translate into production architectures and low-level memory mechanics.