图 
      
    
      
      
      
        并查集 
      
    
      
      
      
        广度优先搜索 
      
    
      
      
      
        深度优先搜索 
      
    
   
  
    
      
       
     
  
  
    
      
    
    
      
       
     
  
题目描述 
存在一个 无向图  ,图中有 n 个节点。其中每个节点都有一个介于 0 到 n - 1 之间的唯一编号。给你一个二维数组 graph ,其中 graph[u] 是一个节点数组,由节点 u 的邻接节点组成。形式上,对于 graph[u] 中的每个 v ,都存在一条位于节点 u 和节点 v 之间的无向边。该无向图同时具有以下属性:
    不存在自环(graph[u] 不包含 u)。 
    不存在平行边(graph[u] 不包含重复值)。 
    如果 v 在 graph[u] 内,那么 u 也应该在 graph[v] 内(该图是无向图) 
    这个图可能不是连通图,也就是说两个节点 u 和 v 之间可能不存在一条连通彼此的路径。 
 
二分图  定义:如果能将一个图的节点集合分割成两个独立的子集 A 和 B ,并使图中的每一条边的两个节点一个来自 A 集合,一个来自 B 集合,就将这个图称为 二分图  。
如果图是二分图,返回 true  ;否则,返回 false 。
 
示例 1: 
输入: graph = [[1,2,3],[0,2],[0,1,3],[0,2]]
输出: false
解释: 不能将节点分割成两个独立的子集,以使每条边都连通一个子集中的一个节点与另一个子集中的一个节点。 
示例 2: 
输入: graph = [[1,3],[0,2],[1,3],[0,2]]
输出: true
解释: 可以将节点分成两组: {0, 2} 和 {1, 3} 。 
 
提示: 
    graph.length == n 
    1 <= n <= 100 
    0 <= graph[u].length < n 
    0 <= graph[u][i] <= n - 1 
    graph[u] 不会包含 u 
    graph[u] 的所有值 互不相同  
    如果 graph[u] 包含 v,那么 graph[v] 也会包含 u 
 
解法 
方法一:染色法判定二分图 
遍历所有节点进行染色,比如初始为白色,DFS 对节点相邻的点染上另外一种颜色。如果要染色某节点时,要染的目标颜色和该节点的已经染过的颜色不同,则说明不能构成二分图。
时间复杂度 \(O(n)\) ,空间复杂度 \(O(n)\) 。其中 \(n\)  为节点数。
Python3 Java C++ Go TypeScript Rust 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 class   Solution : 
    def   isBipartite ( self ,  graph :  List [ List [ int ]])  ->  bool : 
        def   dfs ( a :  int ,  c :  int )  ->  bool : 
            color [ a ]  =  c 
            for  b  in  graph [ a ]: 
                if  color [ b ]  ==  c  or  ( color [ b ]  ==  0  and  not  dfs ( b ,  - c )): 
                    return  False 
            return  True 
        n  =  len ( graph ) 
        color  =  [ 0 ]  *  n 
        for  i  in  range ( n ): 
            if  color [ i ]  ==  0  and  not  dfs ( i ,  1 ): 
                return  False 
        return  True 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 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   a ,   int   c )   { 
         color [ a ]   =   c ; 
         for   ( int   b   :   g [ a ] )   { 
             if   ( color [ b ]   ==   c   ||   ( color [ b ]   ==   0   &&   ! dfs ( b ,   - c )))   { 
                 return   false ; 
             } 
         } 
         return   true ; 
     } 
} 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 class   Solution   { 
public : 
     bool   isBipartite ( vector < vector < int >>&   graph )   { 
         int   n   =   graph . size (); 
         vector < int >   color ( n ); 
         auto   dfs   =   [ & ]( this   auto &&   dfs ,   int   a ,   int   c )   ->   bool   { 
             color [ a ]   =   c ; 
             for   ( int   b   :   graph [ a ])   { 
                 if   ( color [ b ]   ==   c   ||   ( color [ b ]   ==   0   &&   ! dfs ( b ,   - c )))   { 
                     return   false ; 
                 } 
             } 
             return   true ; 
         }; 
         for   ( int   i   =   0 ;   i   <   n ;   ++ i )   { 
             if   ( color [ i ]   ==   0   &&   ! dfs ( i ,   1 ))   { 
                 return   false ; 
             } 
         } 
         return   true ; 
     } 
}; 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 func   isBipartite ( graph   [][] int )   bool   { 
     n   :=   len ( graph ) 
     color   :=   make ([] int ,   n ) 
     var   dfs   func ( int ,   int )   bool 
     dfs   =   func ( a ,   c   int )   bool   { 
         color [ a ]   =   c 
         for   _ ,   b   :=   range   graph [ a ]   { 
             if   color [ b ]   ==   c   ||   ( color [ b ]   ==   0   &&   ! dfs ( b ,   - c ))   { 
                 return   false 
             } 
         } 
         return   true 
     } 
     for   i   :=   range   graph   { 
         if   color [ i ]   ==   0   &&   ! dfs ( i ,   1 )   { 
             return   false 
         } 
     } 
     return   true 
} 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 function   isBipartite ( graph :   number [][]) :   boolean   { 
     const   n   =   graph . length ; 
     const   color :   number []   =   Array ( n ). fill ( 0 ); 
     const   dfs   =   ( a :   number ,   c :   number ) :   boolean   =>   { 
         color [ a ]   =   c ; 
         for   ( const   b   of   graph [ a ])   { 
             if   ( color [ b ]   ===   c   ||   ( color [ b ]   ===   0   &&   ! dfs ( b ,   - c )))   { 
                 return   false ; 
             } 
         } 
         return   true ; 
     }; 
     for   ( let   i   =   0 ;   i   <   n ;   i ++ )   { 
         if   ( color [ i ]   ===   0   &&   ! dfs ( i ,   1 ))   { 
             return   false ; 
         } 
     } 
     return   true ; 
} 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 impl   Solution   { 
     pub   fn   is_bipartite ( graph :   Vec < Vec < i32 >> )   ->   bool   { 
         let   n   =   graph . len (); 
         let   mut   color   =   vec! [ 0 ;   n ]; 
         fn   dfs ( a :   usize ,   c :   i32 ,   graph :   & Vec < Vec < i32 >> ,   color :   & mut   Vec < i32 > )   ->   bool   { 
             color [ a ]   =   c ; 
             for   & b   in   & graph [ a ]   { 
                 if   color [ b   as   usize ]   ==   c 
                     ||   ( color [ b   as   usize ]   ==   0   &&   ! dfs ( b   as   usize ,   - c ,   graph ,   color )) 
                 { 
                     return   false ; 
                 } 
             } 
             true 
         } 
         for   i   in   0 .. n   { 
             if   color [ i ]   ==   0   &&   ! dfs ( i ,   1 ,   & graph ,   & mut   color )   { 
                 return   false ; 
             } 
         } 
         true 
     } 
} 
 
 
 
 
方法二:并查集 
对于本题,如果是二分图,那么图中每个顶点的所有邻接点都应该属于同一集合,且不与顶点处于同一集合,因此我们可以使用并查集。遍历图中每个顶点,如果发现存在当前顶点与对应的邻接点处于同一个集合,说明不是二分图。否则将当前节点的邻接点相互进行合并。
时间复杂度 \(O(n \times \log n)\) ,空间复杂度 \(O(n)\) 。其中 \(n\)  为节点数。
Python3 Java C++ Go TypeScript Rust 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 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 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 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 ] ; 
     } 
} 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 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 ; 
     } 
}; 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 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 
} 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 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 ; 
} 
 
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 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 
     } 
}