LeetCode 785. 判断二分图(每日一题)

430 阅读2分钟

原题链接

785. 判断二分图

1. 二分图定义

简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。(百度百科复制的,感觉还是挺好理解的)

1.1 如何判断为二分图

无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。所以就可以使用染色法来解决问题。

2. 染色法

一共有两种颜色,从其中一个点开始判断,将跟它相连的点染成和它不同的另一种颜色,如果最后相连的点有相同的颜色,则不是二分图。

2.1 BFS 广度优先遍历

/**
 * @param {number[][]} graph
 * @return {boolean}
 */
var isBipartite = function (graph) {
  /* bfs + 染色法 */
  const len = graph.length;
  const colors = new Array(len).fill(0); // 用于存储染色信息的数组,0 表示未染色,1 表示染成红色,2 表示染成绿色

  for (let i = 0; i < len; i++) {
    if (!colors[i]) { // 判断是否被染色,如已染色说明此处已被遍历过了,跳过
      let que = [i]; // 使用队列存储需要被染色的节点下标
      colors[i] = 1; // 初始化第一个的颜色为红色
      while (que.length) { // 通过队列的长度来判断是否结束循环
        const key = que.shift();
        const color = colors[key] === 1 ? 2 : 1; // 记录下该节点的下个节点应该为什么颜色
        for (const item of graph[key]) { // 遍历该节点所有与之相连的节点
          if (colors[item]) { // 如果该节点已被染色,则判断该颜色是否与记录下的颜色一样,不一样则 return false
            if (colors[item] !== color) return false;
          } else { // 如果未被染色,则将其染色,并将其添加进队列中
            colors[item] = color;
            que.push(item);
          }
        }
      }
    }
  }
  return true;
};

2.2 DFS 深度优先遍历

/**
 * @param {number[][]} graph
 * @return {boolean}
 */
var isBipartite = function (graph) {
  /* dfs + 染色法 */
  const colors = new Array(graph.length).fill(0); // 用于存储染色信息的数组,0 表示未染色,1 表示染成红色,2 表示染成绿色
  return colors.every((value, index) => value === 0 ? dfs(index, graph, colors, 1) : true); // 如果已经被染色就不必在递归了
};

const dfs = (i, graph, colors, color) => {
  if (colors[i]) { // 递归出口,如果已被染色,则判断是否与要被染色的颜色一致
    if (colors[i] !== color) return false; // 不一致 return false
    return true; // 一致 return true
  }
  colors[i] = color; // 未被染色,则将其染色
  return graph[i].every(value => dfs(value, graph, colors, color === 1 ? 2 : 1));
};