题目
给定一个无向图graph
,当这个图为二分图时返回true
。
如果我们能将一个图的节点集合分割成两个独立的子集A
和B
,并使图中的每一条边的两个节点一个来自A
集合,一个来自B
集合,我们就将这个图称为二分图。
graph
将会以邻接表方式给出,graph[i]
表示图中与节点i相连的所有节点。每个节点都是一个在0
到graph.length-1
之间的整数。这图中没有自环和平行边:graph[i]
中不存在i
,并且graph[i]
中没有重复的值。
注意点:
graph
的长度范围为[1, 100]
。graph[i]
中的元素的范围为[0, graph.length - 1]
。graph[i]
不会包含i
或者有重复的值。
图是无向的: 如果j
在graph[i]
里边, 那么i
也会在graph[j]
里边。
解题思路
算法的流程如下:
-
我们任选一个节点开始,将其染色,并从该节点开始对整个无向图进行遍历;
-
在遍历的过程中,如果我们通过节点
u
遍历到了节点v
(即u
和v
在图中有一条边直接相连),那么会有两种情况:-
如果
v
未被染色,那么我们将其染成与u
不同的颜色,并对v
直接相连的节点进行遍历; -
如果
v
被染色,并且颜色与u
相同,那么说明给定的无向图不是二分图。我们可以直接退出遍历并返回False
作为答案。
-
-
当遍历结束时,说明给定的无向图是二分图,返回
True
作为答案。扫描二维码关注公众号,回复: 12897386 查看本文章
解法一:广度优先算法
因为题目给的是邻接表,天生适合广度优先算法。
// 广度遍历 bfs
var isBipartite1 = function(graph) {
const colors = new Array(graph.length).fill("N"); // 记录顶点染色,初始化未染色'N',颜色分别是'Y'和'R'
const queue = []; // 辅助队列
let index = 0; // 当前顶点
while (index !== -1) {
colors[index] = "Y"; // 染色
queue.push(index); // 顶点加入队列中
while (queue.length > 0) {
let node = queue.shift(); // 出队
let borderNodeList = graph[node];
let paintColor = colors[node] === "Y" ? "R" : "Y";
// 遍历当前顶点的邻接顶点,判断能否染色
for (let i = 0, len = borderNodeList.length; i < len; ++i) {
if (colors[borderNodeList[i]] === "N") {
colors[borderNodeList[i]] = paintColor;
queue.push(borderNodeList[i]);
} else if (colors[borderNodeList[i]] !== paintColor) {
return false;
}
}
}
index = colors.indexOf("N");
}
return true;
};
解法二:深度优先算法
将大问题分解为一个个子问题,每个子问题的核心是:判断当前顶点v能否正常染色,且其相邻节点能否正常染色。
假设f(i)
表示当前顶点i可否正常染色,那么f(i) = f(i) && f(adjoin(i))
const dfs = (v, graph, colors, color) => {
// 递归出口
if (colors[v] !== "N") {
if (colors[v] !== color) {
return false;
}
return true;
}
// 核心,判断当前节点能否
colors[v] = color;
return graph[v].every(item =>
dfs(item, graph, colors, color === "Y" ? "R" : "Y")
);
};
const isBipartite2 = function(graph) {
let colors = new Array(graph.length).fill("N");
return colors.every((item, index) =>
item === "N" ? dfs(index, graph, colors, "Y") : true
);
};
也可以用栈模拟递归。
// 深度遍历(迭代写法)
var isBipartite = function(graph) {
const colors = new Array(graph.length).fill("N");
const stack = [];
let index = 0;
while (index !== -1) {
colors[index] = "Y";
stack.push(index);
while (stack.length > 0) {
let node = stack.pop();
let borderNodeList = graph[node];
let paintColor = colors[node] === "Y" ? "R" : "Y";
for (let i = 0, len = borderNodeList.length; i < len; ++i) {
if (colors[borderNodeList[i]] === "N") {
colors[borderNodeList[i]] = paintColor;
stack.push(borderNodeList[i]);
} else if (colors[borderNodeList[i]] !== paintColor) {
return false;
}
}
}
index = colors.indexOf("N");
}
return true;
};