题目描述
给定一个无向图graph,当这个图为二分图时返回true。
如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。
graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。
示例 1:
输入:[[1,3], [0,2], [1,3], [0,2]]
输出: true
示例 2:
输入: [[1,2,3], [0,2], [0,1,3], [0,2]]
输出: false
注意:
graph 的长度范围为 [1, 100]。
graph[i] 中的元素的范围为 [0, graph.length - 1]。
graph[i] 不会包含 i 或者有重复的值。
图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。
思路:
按照定义如果是二分图,一个点和它相连的点一定属于不同的集合,于是就可以对点进行标记。如第一个点标记为1,和它相连的点就可以标为2,和标为2的点相连的点标为1。如果要标记的点已经被标为其他数字了,就可以判断不是二分图。如果每个点都能被标记,就是二分图。标记用深搜广搜都可以,懒得写函数就直接队列广搜了。
这题比较坑的是允许孤立的点存在,需要判断一下是不是所有的点都被标记过了。
判断的流程
- 循环遍历vis数组找出没有被标记的第一个点
- 将该点标记为1,压入队列
- 取出队列的第一个点j,对j周围的点进行标记
- 如果周围的点已经被标记过且是和j相同的标记,则说明不是二分图,输出false
- 如果周围的点未被标记,标记为和j不同的数字,并将该点压入队列
- 如果队列为空,回到1,如果队列不为空,回到3
- 如果所有的点都被标记,说明是二分图,返回true
ac代码:
class Solution {
public:
bool isBipartite(vector<vector<int>>& graph) {
vector<int> vis(graph.size(),0);
queue<int> q;
for(int k=0;k<graph.size();k++)
{
if(vis[k]==0)
{
vis[k]=1;
q.push(k);
while(!q.empty())
{
int i=q.front();
q.pop();
for (int j=0;j<graph[i].size();j++)
{
if(vis[graph[i][j]])
{
if(vis[graph[i][j]]==vis[i])
{
return 0;
}
}
else
{
vis[graph[i][j]]=(vis[i]%2)+1;
q.push(graph[i][j]);
}
}
}
}
}
return 1;
}
};