Given an undirected graph, return true if and only if it is bipartite.

Recall that a graph is bipartite if we can split it's set of nodes into two independent subsets A and B such that every edge in the graph has one node in A and another node in B.

The graph is given in the following form: graph[i] is a list of indexes j for which the edge between nodes i and j exists.  Each node is an integer between 0 and graph.length - 1.  There are no self edges or parallel edges: graph[i] does not contain i, and it doesn't contain any element twice.

Example 1:
Input: [[1,3], [0,2], [1,3], [0,2]]
Output: true
Explanation:
The graph looks like this:
0----1
| |
| |
3----2
We can divide the vertices into two groups: {0, 2} and {1, 3}.
Example 2:
Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
Output: false
Explanation:
The graph looks like this:
0----1
| \ |
| \ |
3----2
We cannot find a way to divide the set of nodes into two independent subsets.

Note:

  • graph will have length in range [1, 100].
  • graph[i] will contain integers in range [0, graph.length - 1].
  • graph[i] will not contain i or duplicate values.
  • The graph is undirected: if any element j is in graph[i], then i will be in graph[j].

这道题博主在最开始做的时候,看了半天,愣是没弄懂输出数据的意思,博主开始以为给的是边,后来发现跟图对应不上,就懵逼了,后来是通过研究论坛上大神们的解法,才总算搞懂了题目的意思,原来输入数组中的 graph[i],表示顶点i所有相邻的顶点,比如对于例子1来说,顶点0和顶点1,3相连,顶点1和顶点0,2相连,顶点2和结点1,3相连,顶点3和顶点0,2相连。这道题让我们验证给定的图是否是二分图,所谓二分图,就是可以将图中的所有顶点分成两个不相交的集合,使得同一个集合的顶点不相连。为了验证是否有这样的两个不相交的集合存在,我们采用一种很机智的染色法,大体上的思路是要将相连的两个顶点染成不同的颜色,一旦在染的过程中发现有两连的两个顶点已经被染成相同的颜色,说明不是二分图。这里我们使用两种颜色,分别用1和 -1 来表示,初始时每个顶点用0表示未染色,然后遍历每一个顶点,如果该顶点未被访问过,则调用递归函数,如果返回 false,那么说明不是二分图,则直接返回 false。如果循环退出后没有返回 false,则返回 true。在递归函数中,如果当前顶点已经染色,如果该顶点的颜色和将要染的颜色相同,则返回 true,否则返回 false。如果没被染色,则将当前顶点染色,然后再遍历与该顶点相连的所有的顶点,调用递归函数,如果返回 false 了,则当前递归函数的返回 false,循环结束返回 true,参见代码如下:

解法一:

class Solution {
public:
bool isBipartite(vector<vector<int>>& graph) {
vector<int> colors(graph.size());
for (int i = ; i < graph.size(); ++i) {
if (colors[i] == && !valid(graph, , i, colors)) {
return false;
}
}
return true;
}
bool valid(vector<vector<int>>& graph, int color, int cur, vector<int>& colors) {
if (colors[cur] != ) return colors[cur] == color;
colors[cur] = color;
for (int i : graph[cur]) {
if (!valid(graph, - * color, i, colors)) {
return false;
}
}
return true;
}
};

我们再来看一种迭代的解法,整体思路还是一样的,还是遍历整个顶点,如果未被染色,则先染色为1,然后使用 BFS 进行遍历,将当前顶点放入队列 queue 中,然后 while 循环 queue 不为空,取出队首元素,遍历其所有相邻的顶点,如果相邻顶点未被染色,则染成和当前顶点相反的颜色,然后把相邻顶点加入 queue 中,否则如果当前顶点和相邻顶点颜色相同,直接返回 false,循环退出后返回 true,参见代码如下:

解法二:

class Solution {
public:
bool isBipartite(vector<vector<int>>& graph) {
vector<int> colors(graph.size());
for (int i = ; i < graph.size(); ++i) {
if (colors[i] != ) continue;
colors[i] = ;
queue<int> q{{i}};
while (!q.empty()) {
int t = q.front(); q.pop();
for (auto a : graph[t]) {
if (colors[a] == colors[t]) return false;
if (colors[a] == ) {
colors[a] = - * colors[t];
q.push(a);
}
}
}
}
return true;
}
};

其实这道题还可以使用并查集 Union Find 来做,所谓的并查集,简单来说,就是归类,将同一集合的元素放在一起。我们开始遍历所有结点,若当前结点没有邻接结点,直接跳过。否则就要开始进行处理了,并查集方法的核心就两步,合并跟查询。我们首先进行查询操作,对当前结点和其第一个邻接结点分别调用 find 函数,如果其返回值相同,则意味着其属于同一个集合了,这是不合题意的,直接返回 false。否则我们继续遍历其他的邻接结点,对于每一个新的邻接结点,我们都调用 find 函数,还是判断若返回值跟原结点的相同,return false。否则就要进行合并操作了,根据敌人的敌人就是朋友的原则,所有的邻接结点之间应该属于同一个组,因为就两个组,我所有不爽的人都不能跟我在一个组,那么他们所有人只能都在另一个组,所以需要将他们都合并起来,合并的时候不管是用 root[parent] = y 还是 root[g[i][j]] = y 都是可以,因为不管直接跟某个结点合并,或者跟其祖宗合并,最终经过 find 函数追踪溯源都会返回相同的值,参见代码如下:

解法三:

class Solution {
public:
bool isBipartite(vector<vector<int>>& graph) {
vector<int> root(graph.size());
for (int i = ; i < graph.size(); ++i) root[i] = i;
for (int i = ; i < graph.size(); ++i) {
if (graph[i].empty()) continue;
int x = find(root, i), y = find(root, graph[i][]);
if (x == y) return false;
for (int j = ; j < graph[i].size(); ++j) {
int parent = find(root, graph[i][j]);
if (x == parent) return false;
root[parent] = y;
}
}
return true;
}
int find(vector<int>& root, int i) {
return root[i] == i ? i : find(root, root[i]);
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/785

类似题目:

Possible Bipartition

参考资料:

https://leetcode.com/problems/is-graph-bipartite/

https://leetcode.com/problems/is-graph-bipartite/discuss/115487/Java-Clean-DFS-solution-with-Explanation

https://leetcode.com/problems/is-graph-bipartite/discuss/115723/C++-short-iterative-solution-with-comments

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Is Graph Bipartite? 是二分图么?的更多相关文章

  1. [LeetCode] 785. Is Graph Bipartite? 是二分图么?

    Given an undirected graph, return true if and only if it is bipartite. Recall that a graph is bipart ...

  2. LeetCode - Is Graph Bipartite?

    Given an undirected graph, return true if and only if it is bipartite. Recall that a graph is bipart ...

  3. [leetcode]785. Is Graph Bipartite? [bai'pɑrtait] 判断二分图

    Given an undirected graph, return true if and only if it is bipartite. Example 1: Input: [[1,3], [0, ...

  4. 【LeetCode】785. Is Graph Bipartite? 解题报告(Python)

    [LeetCode]785. Is Graph Bipartite? 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu. ...

  5. [LeetCode] Possible Bipartition 可能的二分图

    Given a set of N people (numbered 1, 2, ..., N), we would like to split everyone into two groups of  ...

  6. [Swift]LeetCode785. 判断二分图 | Is Graph Bipartite?

    Given an undirected graph, return true if and only if it is bipartite. Recall that a graph is bipart ...

  7. LeetCode 785. Is Graph Bipartite?

    原题链接在这里:https://leetcode.com/problems/is-graph-bipartite/ 题目: Given an undirected graph, return true ...

  8. [LeetCode] 785. Is Graph Bipartite?_Medium tag: DFS, BFS

    Given an undirected graph, return true if and only if it is bipartite. Recall that a graph is bipart ...

  9. Edge coloring of bipartite graph CodeForces - 600F (二分图染色)

    大意:给定二分图, 求将边染色, 使得任意邻接边不同色且使用颜色种类数最少 最少颜色数即为最大度数, 要输出方案的话, 对于每一条边(u,v), 求出u,v能使用的最小的颜色$t0$,$t1$ 若t0 ...

随机推荐

  1. USB Audio设计与实现

    1 前言 本文将基于STM32F4 Discovery板,从零开始设计并实现一个USB Audio的例子. 2 设计构思 所谓的USB AUDIO就是制作一个盒子,这个盒子可以通过USB连接到PC,P ...

  2. [luogu1402]酒店之王_网络流

    酒店之王 luogu-1402 题目大意:有n个人,p道菜,q个房间,每个人喜欢吃一些菜.喜欢住一些房间,如果一个人即住到了他喜欢的房间有吃到了他喜欢的菜,就对答案贡献++,求最大贡献. 注释:1&l ...

  3. 设计模式之 外观模式详解(Service第三者插足,让action与dao分手)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,LZ今天给各位分享一 ...

  4. Java创建线程的三种方式

    一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实 ...

  5. Android破解心得——记学习七少月安卓大型安全公开课

    第一课 讲解了关于在安卓破解之中环境的配置及所需要用到的软件,重要的软件是Androidkiller,安卓逆向助手 第二课讲解了java与smali的关系,从smail角度详细的分析了一个简单的Hel ...

  6. 面试常考---html篇

    1.html5新特性,语义化 HTML5为我们提供了一系列的语义标签. 1.<section></section> 定义文档中的主体部分的节.段. 2.<article& ...

  7. C 连接mysql VC的步骤

    初学C,看到C 连接mysql的教程不是很多,遇到很多的问题,看过许多盟友的解决方法,有点模糊(对我这个菜鸟来说),下面贴出具体步骤,一起学习: 1.C连接mysql的方法:C ,C ++ ,ODBC ...

  8. 配置 CSV Data Set Config 来参数化新增客户信息操作

    1.首先根据新增客户信息的http请求,来确定需要参数化的变量,选取符合测试需求且经常变化或未来会变化的变量为需要参数化的变量,如本文中的客户端名称(sys_name).描述(description) ...

  9. Alpha第八天

    Alpha第八天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  10. 安利给班里的大家一个chrome的GitHub插件-----gayhub

    title: 一个好用的Github插件--gayhub date: 2017-09-20 15:41:36 tags: --- 别跑, 这真是正经插件. 效果, 一图流: 具体效果在项目地址很详细 ...