剑指offer106:二分图

题目:
存在一个 无向图 ,图中有 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 。
示例一:
在这里插入图片描述
输入:graph = [[1,2,3],[0,2],[0,1,3],[0,2]]
输出:false
解释:不能将节点分割成两个独立的子集,以使每条边都连通一个子集中的一个节点与另一个子集中的一个节点。
示例二:
在这里插入图片描述
输入:graph = [[1,3],[0,2],[1,3],[0,2]]
输出:true
解释:可以将节点分成两组: {0, 2} 和 {1, 3} 。

分析:
二分图的节点可以分成两种不同的类型,任意一条边的两个节点分别属于两种不同的类型,可以为图中的所有节点着色,两种不同类型的节点分别涂上不同的颜色,如果一条边的两个节点都能被涂上不同的颜色,那么整个图就是一个二分图。如果一个图中有n个节点,创建一个长度为n的数组colors记录每个节点的颜色,节点i的颜色保存在colors[i]中,如果节点i还没有被着色,那么colors[i]的值为-1,如果节点i已经被着色,那么colors[i]的值为0或1。
函数setColor用来以节点i为起始节点的一个连通子图着色,它的返回值用来表示能否按照二分图的规则对子图的所有节点进行着色,为了能够给所有节点着色,需要搜索所有与节点连通的点,每搜索到一个尚未着色的节点就按照二分图的规则给它涂上颜色。
具体采用的两种搜索方式详见代码
代码:

package com.kuang;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class IsBipartite {
    
    
    public boolean isBipartite(int[][] graph) {
    
    
        int size = graph.length;
        int[] colors = new int[size];
        Arrays.fill(colors,-1);
        for (int i = 0; i < size; i++) {
    
    
            if (colors[i] == -1){
    
    
                if (!setColor(graph,colors,i,0)){
    
    
                    return false;
                }
            }
        }
        return true;
    }
//利用广度优先搜索对子图着色
    private boolean setColor(int[][] graph, int[] colors, int i, int color) {
    
    
        Queue<Integer> queue = new LinkedList<>();
        queue.add(i);
        colors[i] = color;
        while (!queue.isEmpty()){
    
    
            int v = queue.remove();
            for (int neigbor : graph[v]){
    
    
                if (colors[neigbor] >= 0){
    
    
                    if (colors[neigbor] == colors[v]){
    
    
                        return false;
                    }
                }else {
    
    
                    queue.add(neigbor);
                    colors[neigbor] = 1 - colors[v];
                }
            }
        }
        return true;
    }
//    利用深度优先搜索对子图着色,setColor1将节点i的颜色设置为color
private boolean setColor1(int[][] graph, int[] colors, int i, int color){
    
    
        if (colors[i] >= 0){
    
    
//            如果相邻节点有颜色,并且和相邻节点颜色相同则返回false
            return colors[i] == color;
        }
//        给当前节点着色
        colors[i] = color;
//        遍历该节点的邻节点
        for (int neighbor : graph[i]){
    
    
//            给该节点的邻节点着另一个颜色
            if (!setColor1(graph,colors,neighbor,1-color)){
    
    
                return false;
            }
        }
        return true;
}
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Jiaodaqiaobiluo/article/details/123841037
今日推荐