0% completed
Problem Statement
Given a 2D array graph[][]
, representing the undirected graph
, where graph[u]
is an array of nodes that are connected with node u
.
Determine whether a given undirected graph is a bipartite graph
.
The graph is a bipartite graph
, if we can split
the set of nodes into two distinct subsets
such that no two nodes within the same subset are adjacent
(i.e., no edge exists between any two nodes within a single subset).
Examples
- Example 1:
- Input: graph =
[[1,3], [0,2], [1,3], [0,2]]
- Input: graph =
- Expected Output:
true
- Justification: The nodes can be divided into two groups: {0, 2} and {1, 3}. No two nodes within each group are adjacent, thus the graph is bipartite.
- Example 2:
- Input: graph =
[[1], [0], [3], [2]]
- Input: graph =
- Expected Output:
true
- Justification: The graph is a simple chain of 4 nodes. It's clearly bipartite as we can have {0, 2} and {1, 3} as the two subsets.
- Example 3:
- Input: graph =
[[1,2,3],[0,2],[0,1,3],[0,2]]
- Input: graph =
- Expected Output:
false
- Justification: We found that edges (1, 2), (0, 3), and (2, 3) connect nodes within the same set, which violates the condition for a bipartite graph where each edge must connect nodes in different subsets. Thus, there's no way to divide this graph into two subsets that satisfy the bipartite condition.
Constraints:
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 of graph[u] are unique.
- If
graph[u]
contains v, thengraph[v]
contains u.
Solution
Algorithm Description
The algorithm for determining if a graph is bipartite uses the Union-Find data structure, enhanced with path compression and union by rank. The primary goal is to ensure that no two adjacent nodes are in the same set, which would indicate that the graph is not bipartite.
Initially, each node is its own parent, and all ranks are set to zero. The algorithm then iterates through each node and its neighbors. For each node, it selects the first neighbor as a representative to which other neighbors will be compared. This is done to ensure that all neighbors of a node are placed in the opposite set. By attempting to union each neighbor with the first neighbor, we effectively check if all neighbors can be grouped together in a way that maintains the bipartite property.
If, during this process, a neighbor is found to be in the same set as the current node (i.e., they have the same root), it indicates that the graph is not bipartite, and the function returns false. If no such conflict is detected after processing all nodes, the graph is bipartite, and the function returns true. This method ensures efficient and accurate detection of bipartite graphs using the Union-Find structure.
Step-by-Step Algorithm
-
Initialization:
- Create arrays
parent
andrank
of size equal to the number of nodes. - Initialize each node as its own parent in the
parent
array. - Initialize the
rank
array with zeros.
- Create arrays
-
Iterate through each node:
- For each node
u
:- If
u
has no edges, continue to the next node. - Find the root of node
u
using thefind
operation. - Select the first neighbor of
u
as the representative neighbor.
- If
- For each node
-
Check neighbors and perform union operations:
- For each neighbor
v
of nodeu
:- If the root of
u
is the same as the root ofv
, a conflict is detected, and the graph is not bipartite. Returnfalse
. - Otherwise, perform a union operation between the first neighbor and the current neighbor
v
.
- If the root of
- For each neighbor
-
Return result:
- If no conflicts are found after processing all nodes, return
true
.
- If no conflicts are found after processing all nodes, return
Algorithm Walkthrough
For the input [[1,3], [0,2], [1,3], [0,2]]
:
-
Initialization:
parent = [0, 1, 2, 3]
rank = [0, 0, 0, 0]
-
First Node (u = 0):
- Neighbors: [1, 3]
find(0)
: Returns 0 (root of 0 is 0)- First neighbor: 1
- Neighbor (v = 1):
find(1)
: Returns 1 (root of 1 is 1)- Roots of
0
and1
are different. Performunion(1, 1)
:find(1)
: Returns 1find(1)
: Returns 1- Roots are the same. No change in
parent
andrank
.
- Neighbor (v = 3):
find(3)
: Returns 3 (root of 3 is 3)- Roots of
0
and3
are different. Performunion(1, 3)
:find(1)
: Returns 1find(3)
: Returns 3
rank[1] == rank[3]
, soparent[3] = 1
andrank[1]++
. Updatedparent = [0, 1, 2, 1]
,rank = [0, 1, 0, 0]
.
-
Second Node (u = 1):
- Neighbors: [0, 2]
find(1)
: Returns 1 (root of 1 is 1)- First neighbor: 0
- Neighbor (v = 0):
find(0)
: Returns 0 (root of 0 is 0)- Roots of
1
and0
are different. Performunion(0, 0)
:find(0)
: Returns 0find(0)
: Returns 0- Roots are the same. No change in
parent
andrank
.
- Neighbor (v = 2):
find(2)
: Returns 2 (root of 2 is 2)- Roots are different. Perform
union(0, 2)
:find(0)
: Returns 0find(2)
: Returns 2rank[0] == rank[2]
, soparent[2] = 0
andrank[0]++
. Updatedparent = [0, 1, 0, 1]
,rank = [1, 0, 0, 0]
.
-
Third Node (u = 2):
- Neighbors: [1, 3]
find(2)
: Returns 0 (root of 2 is 0)- First neighbor: 1
- Neighbor (v = 1):
find(1)
: Returns 1 (root of 1 is 1)- Roots are different. Perform
union(1, 1)
:find(1)
: Returns 1find(1)
: Returns 1- Roots are the same. No change in
parent
andrank
.
- Neighbor (v = 3):
find(3)
: Returns 1 (root of 3 is 1)- Roots are different. Perform
union(1, 3)
:find(1)
: Returns 1find(3)
: Returns 1- Roots are the same. No change in
parent
andrank
.
-
Fourth Node (u = 3):
- Neighbors: [0, 2]
find(3)
: Returns 1 (root of 3 is 1)- First neighbor: 0
- Neighbor (v = 0):
find(0)
: Returns 0 (root of 0 is 0)- Roots are different. Perform
union(0, 0)
:find(0)
: Returns 0find(0)
: Returns 0- Roots are the same. No change in
parent
andrank
.
- Neighbor (v = 2):
find(2)
: Returns 0 (root of 2 is 0)- Roots are different. Perform
union(0, 2)
:find(0)
: Returns 0find(2)
: Returns 2- Roots are the same. No change in
parent
andrank
.
No conflict is detected. So, the graph is not bipartite.
Code
Complexity Analysis
Time Complexity
-
- Initializing the
parent
andrank
arrays takes O(N) time, where N is the number of nodes in the graph.
- Initializing the
-
Processing each node:
- For each node
u
, the code checks its neighbors. - Finding the parent set of each node using the
Find
method takes nearly constant time, O(α(N)), where α is the inverse Ackermann function, which grows very slowly. - Performing the union operation also takes nearly constant time, O(α(N)).
- The nested loop iterates over all edges in the graph. If we denote the total number of edges by E, then iterating over all edges will take O(E) time.
- For each node
-
Total Time Complexity:
- Combining all, the overall time complexity is O((N + E) * α(N)), which simplifies to O(N + E) in practical scenarios because α(N) is very small and can be considered a constant.
Space Complexity
-
Space for
parent
andrank
arrays:- The space required for the
parent
array is O(N). - The space required for the
rank
array is O(N).
- The space required for the
-
Total Space Complexity:
- The overall space complexity is O(N), which is needed for the
parent
andrank
arrays.
- The overall space complexity is O(N), which is needed for the
.....
.....
.....
Table of Contents
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible