#785 Is Graph Bipartite?

这篇博客探讨了如何判断一个无向图是否为二分图。首先,介绍了使用递归的方法,通过设置两个节点集合A和B,尝试将边连接的节点分配到不同集合中。当无法找到合适的分配方式时,返回false。如果所有边都能正确分配,返回true。然后,提出了使用BFS的着色方法,通过为每个节点分配颜色1或-1,确保相邻节点颜色不同,以此判断二分图。最后,给出了两种方法的实现代码,包括递归和BFS版本。
摘要由CSDN通过智能技术生成

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.

Examples

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.

思路

我的思路还是分两步走,毕竟对图还不是很熟悉,所以最开始的时候想的就是用递归的方式暴力求解,这个方法需要建立两个数组 setA 和 setB,这两个数组就存储了二部图中的“二部”,即节点位置,那么每次递归的时候需要进行的判断和操作就是

  • 起点和终点是不是同时包含在 A 或 B 中?是 → 不构成二部图
  • 起点包含在 A 中 或 终点包含在 B 中?是 → 构建 A[起点]-B[终点] ,递归找下一条edge,并返回递归结果
  • 起点包含在 B 中 或 终点包含在 A 中?是 → 构建 B[起点]-A[终点],递归找下一条edge,并返回递归结果
  • 起点和终点 都不包含在 A/B 中?是 → 逐步讨论:构建 A[起点]-B[终点] ,递归找下一条edge
    • 如果返回递归结果为 true,返回 true
    • 如果返回递归结果为 false,恢复到构建 A[起点]-B[终点] 这一步之前的 A/B(因为在后续递归中会改变其他数值,所以不能单纯的只改动起点和终点对应的数值),然后构建 B[起点]-A[终点],归找下一条edge,并返回递归结果

当然上面这个方法不仅复杂,而且代码写起来也很繁琐。

后来就去偷了一下discussion,果然,可以用着色方法进行操作,同时,这种取决于one-move/two-moves 的着色方式会更适用于BFS(我这里用的是BFS,但是看accept里面DFS的速度会更快,不过我认为BFS写起来更容易理解,所以还是只用了BFS)
着色方法指的是:因为是构建二部图,所以如果我能将整张图的节点用两种颜色进行表示,且一条edge链接的两条节点都不属于同一个颜色,那他就是一张二部图。
对BFS来说,我设置当前节点为color1,那我的所有children(one-step-move)就应该都是color2,否则则不构成二部图

这里我用的是color = 1/-1,这样初始化的时候是0,可以区分visited和unvisited,同时通过-color直接获得下一层应该取得颜色

代码

递归解法

class Solution {
    int[] setA, setB;
    
    public boolean recurrsive(int[][] graph, int i, int j) {
        while (j >= graph[i].length) {
            i = i + 1;
            j = 0;
            if (i >= graph.length) {
                return true;
            }
        }
        
        int u = i;
        int v = graph[i][j];
        
        if ((setA[u] == 1 && setA[v] == 1) || (setB[u] == 1 && setB[v] == 1))
            return false;
        
        if (setA[u] == 1 || setB[v] == 1) {
            int tmpA = setA[u];
            int tmpB = setB[v];
            setA[u] = 1;
            setB[v] = 1;
            return recurrsive(graph, i, j + 1);
        }
        
        if (setA[v] == 1 || setB[u] == 1) {
            int tmpA = setA[v];
            int tmpB = setB[u];
            setA[v] = 1;
            setB[u] = 1;
            return recurrsive(graph, i, j + 1);
        }
        
        int[] tmpSetA =  Arrays.copyOf(setA, graph.length);
        int[] tmpSetB =  Arrays.copyOf(setB, graph.length);
        setA[u] = 1;
        setB[v] = 1;
        if (recurrsive(graph, i, j + 1))
            return true;
        setA =  Arrays.copyOf(tmpSetA, graph.length);
        setB =  Arrays.copyOf(tmpSetB, graph.length);
        
        setA[v] = 1;
        setB[u] = 1;
        return recurrsive(graph, i, j + 1);
    }
    
    public boolean isBipartite(int[][] graph) {
        setA = new int[graph.length];
        setB = new int[graph.length];
        
        return recurrsive(graph, 0, 0);
    }
}

BFS解法

class Solution {
    public boolean isBipartite(int[][] graph) {
        int[] color = new int[graph.length];
        List<Integer> queue = new ArrayList<>();
        
        for (int i = 0; i < graph.length; i++){
            if (color[i] != 0)
                continue;
            
            queue.add(i);
            color[i] = 1;
            while (queue.size() > 0){
                int u = queue.get(0);
                int thisLayerColor = -color[u];
                int[] children = graph[u];
                for (int child: children){
                    if (color[child] == -thisLayerColor)
                        return false;
                    if (color[child] == 0){
                        color[child] = thisLayerColor;
                        queue.add(child);
                    } 
                }
                queue.remove(0);
            }
        }
        
        return true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值