[JavaScript / leetcode] 886. 可能的二分法

100 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

每日刷题 2022.10.16

题目

  • 给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。
  • 给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和  bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false。

示例

  • 示例1
输入: n = 4, dislikes = [[1,2],[1,3],[2,4]]
输出: true
解释: group1 [1,4], group2 [2,3]
  • 示例2
输入: n = 3, dislikes = [[1,2],[1,3],[2,3]]
输出: false
  • 示例3
输入: n = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
输出: false

提示

  • 1 <= n <= 2000
  • 0 <= dislikes.length <= 104
  • dislikes[i].length == 2
  • 1 <= dislikes[i][j] <= n
  • ai < bi
  • dislikes 中每一组都 不同

解题思路

  • 这题本质上是考察二分图的判定
  • 如果你把每个人看做图中的节点,相互讨厌的关系看做图中的边,那么 dislikes 数组就可以构成一幅图
  • 又因为题目说互相讨厌的人不能放在同一组里,相当于图中的所有相邻节点都要放进两个不同的组
  • 那就回到了「双色问题」,如果能够用两种颜色着色所有节点,且相邻节点颜色都不同
  • 把 dislikes 构造成一幅图,然后执行二分图的判定算法

AC代码

/**
 * @param {number} n
 * @param {number[][]} dislikes
 * @return {boolean}
 */
var possibleBipartition = function (n, dislikes) {
  let ok = true;
  // 图节点编号从 1 开始
  let color = new Array(n + 1).fill(false);
  let visited = new Array(n + 1).fill(false);
  const buildGraph = (n, dislikes) => {
    // 图节点编号为 1...n
    let graph = new Array(n + 1).fill(0).map(() => new Array());
    for (let edge of dislikes) {
      let v = edge[1];
      let w = edge[0];
      // 「无向图」相当于「双向图」
      // v -> w
      graph[v].push(w);
      // w -> v
      graph[w].push(v);
    }
    return graph;
  };
  const traverse = (graph, v) => {
    if (!ok) return;
    visited[v] = true;
    for (let w of graph[v]) {
      if (!visited[w]) {
        /**
         * 相邻节点 w 没有被访问过
         * 那么应该给节点 w 涂上和节点 v 不同的颜色
         */
        color[w] = !color[v];
        // 继续遍历 w
        traverse(graph, w);
      } else {
        /**
         * 相邻节点 w 已经被访问过
         * 根据 v 和 w 的颜色判断是否是二分图
         */
        if (color[w] == color[v]) ok = false;
      }
    }
  };

  // 转化成邻接表表示图结构
  const graph = buildGraph(n, dislikes);
  for (let i = 1; i <= n; i++) {
    if (!visited[i]) traverse(graph, i);
  }
  return ok;
};