Welcome to Subscribe On Youtube

785. Is Graph Bipartite

Description

There is an undirected graph with n nodes, where each node is numbered between 0 and n - 1. You are given a 2D array graph, where graph[u] is an array of nodes that node u is adjacent to. More formally, for each v in graph[u], there is an undirected edge between node u and node v. The graph has the following properties:

  • There are no self-edges (graph[u] does not contain u).
  • There are no parallel edges (graph[u] does not contain duplicate values).
  • If v is in graph[u], then u is in graph[v] (the graph is undirected).
  • The graph may not be connected, meaning there may be two nodes u and v such that there is no path between them.

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.

Return true if and only if it is bipartite.

 

Example 1:

Input: graph = [[1,2,3],[0,2],[0,1,3],[0,2]]
Output: false
Explanation: There is no way to partition the nodes into two independent sets such that every edge connects a node in one and a node in the other.

Example 2:

Input: graph = [[1,3],[0,2],[1,3],[0,2]]
Output: true
Explanation: We can partition the nodes into two sets: {0, 2} and {1, 3}.

 

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, then graph[v] contains u.

Solutions

Solution 1: Coloring Method to Determine Bipartite Graph

Traverse all nodes for coloring. For example, initially color them white, and use DFS to color the adjacent nodes with another color. If the target color to be colored is different from the color that the node has already been colored, it means that it cannot form a bipartite graph.

The time complexity is $O(n)$, and the space complexity is $O(n)$. Where $n$ is the number of nodes.

Solution 2: Union-Find

For this problem, if it is a bipartite graph, then all adjacent nodes of each vertex in the graph should belong to the same set and not be in the same set as the vertex. Therefore, we can use the union-find method. Traverse each vertex in the graph, and if it is found that the current vertex and its corresponding adjacent nodes are in the same set, it means that it is not a bipartite graph. Otherwise, merge the adjacent nodes of the current node.

The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$. Where $n$ is the number of nodes.

  • class Solution {
        private int[] color;
        private int[][] g;
    
        public boolean isBipartite(int[][] graph) {
            int n = graph.length;
            color = new int[n];
            g = graph;
            for (int i = 0; i < n; ++i) {
                if (color[i] == 0 && !dfs(i, 1)) {
                    return false;
                }
            }
            return true;
        }
    
        private boolean dfs(int u, int c) {
            color[u] = c;
            for (int v : g[u]) {
                if (color[v] == 0) {
                    if (!dfs(v, 3 - c)) {
                        return false;
                    }
                } else if (color[v] == c) {
                    return false;
                }
            }
            return true;
        }
    }
    
    
    // Solution 2
    class Solution {
        private int[] p;
    
        public boolean isBipartite(int[][] graph) {
            int n = graph.length;
            p = new int[n];
            for (int i = 0; i < n; ++i) {
                p[i] = i;
            }
            for (int a = 0; a < n; ++a) {
                for (int b : graph[a]) {
                    int pa = find(a), pb = find(b);
                    if (pa == pb) {
                        return false;
                    }
                    p[pb] = find(graph[a][0]);
                }
            }
            return true;
        }
    
        private int find(int x) {
            if (p[x] != x) {
                p[x] = find(p[x]);
            }
            return p[x];
        }
    }
    
    
  • class Solution {
    public:
        bool isBipartite(vector<vector<int>>& graph) {
            int n = graph.size();
            vector<int> color(n);
            for (int i = 0; i < n; ++i)
                if (!color[i] && !dfs(i, 1, color, graph))
                    return false;
            return true;
        }
    
        bool dfs(int u, int c, vector<int>& color, vector<vector<int>>& g) {
            color[u] = c;
            for (int& v : g[u]) {
                if (!color[v]) {
                    if (!dfs(v, 3 - c, color, g)) return false;
                } else if (color[v] == c)
                    return false;
            }
            return true;
        }
    };
    
    
    // Solution 2
    class Solution {
    public:
        bool isBipartite(vector<vector<int>>& graph) {
            int n = graph.size();
            vector<int> p(n);
            iota(p.begin(), p.end(), 0);
            auto find = [&](this auto&& find, int x) -> int {
                if (p[x] != x) {
                    p[x] = find(p[x]);
                }
                return p[x];
            };
            for (int a = 0; a < n; ++a) {
                for (int b : graph[a]) {
                    int pa = find(a), pb = find(b);
                    if (pa == pb) {
                        return false;
                    }
                    p[pb] = find(graph[a][0]);
                }
            }
            return true;
        }
    };
    
    
  • class Solution:
        def isBipartite(self, graph: List[List[int]]) -> bool:
            def dfs(u, c):
                color[u] = c
                for v in graph[u]:
                    if not color[v]:
                        if not dfs(v, 3 - c):
                            return False
                    elif color[v] == c:
                        return False
                return True
    
            n = len(graph)
            color = [0] * n
            for i in range(n):
                if not color[i] and not dfs(i, 1):
                    return False
            return True
    
    
    # Solution 2
    class Solution:
        def isBipartite(self, graph: List[List[int]]) -> bool:
            def find(x: int) -> int:
                if p[x] != x:
                    p[x] = find(p[x])
                return p[x]
    
            p = list(range(len(graph)))
            for a, bs in enumerate(graph):
                for b in bs:
                    pa, pb = find(a), find(b)
                    if pa == pb:
                        return False
                    p[pb] = find(bs[0])
            return True
    
    
  • func isBipartite(graph [][]int) bool {
    	n := len(graph)
    	color := make([]int, n)
    	var dfs func(u, c int) bool
    	dfs = func(u, c int) bool {
    		color[u] = c
    		for _, v := range graph[u] {
    			if color[v] == 0 {
    				if !dfs(v, 3-c) {
    					return false
    				}
    			} else if color[v] == c {
    				return false
    			}
    		}
    		return true
    	}
    	for i := range graph {
    		if color[i] == 0 && !dfs(i, 1) {
    			return false
    		}
    	}
    	return true
    }
    
    
    // Solution 2
    func isBipartite(graph [][]int) bool {
    	n := len(graph)
    	p := make([]int, n)
    	for i := range p {
    		p[i] = i
    	}
    	var find func(x int) int
    	find = func(x int) int {
    		if p[x] != x {
    			p[x] = find(p[x])
    		}
    		return p[x]
    	}
    	for a, bs := range graph {
    		for _, b := range bs {
    			pa, pb := find(a), find(b)
    			if pa == pb {
    				return false
    			}
    			p[pb] = find(bs[0])
    		}
    	}
    	return true
    }
    
    
  • function isBipartite(graph: number[][]): boolean {
        const n = graph.length;
        let valid = true;
        let colors = new Array(n).fill(0);
        function dfs(idx: number, color: number, graph: number[][]) {
            colors[idx] = color;
            const nextColor = 3 - color;
            for (let j of graph[idx]) {
                if (!colors[j]) {
                    dfs(j, nextColor, graph);
                    if (!valid) return;
                } else if (colors[j] != nextColor) {
                    valid = false;
                    return;
                }
            }
        }
    
        for (let i = 0; i < n && valid; i++) {
            if (!colors[i]) {
                dfs(i, 1, graph);
            }
        }
        return valid;
    }
    
    
    // Solution 2
    function isBipartite(graph: number[][]): boolean {
        const n = graph.length;
        const p: number[] = Array.from({ length: n }, (_, i) => i);
        const find = (x: number): number => {
            if (x !== p[x]) {
                p[x] = find(p[x]);
            }
            return p[x];
        };
        for (let a = 0; a < n; ++a) {
            for (const b of graph[a]) {
                const [pa, pb] = [find(a), find(b)];
                if (pa === pb) {
                    return false;
                }
                p[pb] = find(graph[a][0]);
            }
        }
        return true;
    }
    
    
  • impl Solution {
        #[allow(dead_code)]
        pub fn is_bipartite(graph: Vec<Vec<i32>>) -> bool {
            let mut graph = graph;
            let n = graph.len();
            let mut color_vec: Vec<usize> = vec![0; n];
            for i in 0..n {
                if color_vec[i] == 0 && !Self::traverse(i, 1, &mut color_vec, &mut graph) {
                    return false;
                }
            }
            true
        }
    
        #[allow(dead_code)]
        fn traverse(
            v: usize,
            color: usize,
            color_vec: &mut Vec<usize>,
            graph: &mut Vec<Vec<i32>>
        ) -> bool {
            color_vec[v] = color;
            for n in graph[v].clone() {
                if color_vec[n as usize] == 0 {
                    // This node hasn't been colored
                    if !Self::traverse(n as usize, 3 - color, color_vec, graph) {
                        return false;
                    }
                } else if color_vec[n as usize] == color {
                    // The color is the same
                    return false;
                }
            }
            true
        }
    }
    
    
    // Solution 2
    impl Solution {
        pub fn is_bipartite(graph: Vec<Vec<i32>>) -> bool {
            let n = graph.len();
            let mut p: Vec<usize> = (0..n).collect();
    
            fn find(x: usize, p: &mut Vec<usize>) -> usize {
                if p[x] != x {
                    p[x] = find(p[x], p);
                }
                p[x]
            }
    
            for a in 0..n {
                for &b in &graph[a] {
                    let pa = find(a, &mut p);
                    let pb = find(b as usize, &mut p);
                    if pa == pb {
                        return false;
                    }
                    p[pb] = find(graph[a][0] as usize, &mut p);
                }
            }
            true
        }
    }
    
    

All Problems

All Solutions