可能的二分法

80 阅读1分钟

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

886. 可能的二分法 - 力扣(LeetCode)

给定一组 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 <= 10^4
  • dislikes[i].length == 2
  • 1 <= dislikes[i][j] <= n
  • ai < bi
  • dislikes 中每一组都 不同

思路

本题可以用深度优先搜索来解。假设第一组为A组,第二组为B组,依此遍历每个人,如果当前人没有被分组,就将其分到A组,那么这个不喜欢的人必定被分到B组,被分到B组的人,其不喜欢的人必定被分到A组,以此类推。如果分组过程中存在冲突,就表示不存在解,否则就说明可以分组,有正确解。

解题

/**
 * @param {number} n
 * @param {number[][]} dislikes
 * @return {boolean}
 */
var possibleBipartition = function (n, dislikes) {
  if (dislikes.length <= 1) return true;
  const dfs = (curr, nowColor, color, g) => {
    color[curr] = nowColor;
    for (let i = 0; i < g[curr].length; i++) {
      if (color[g[curr][i]] === 0) {
        if (!dfs(g[curr][i], 3 ^ nowColor, color, g)) {
          return false;
        }
      } else if (color[g[curr][i]] === nowColor) {
        return false;
      }
    }
    return true;
  };
  const color = new Array(n + 1).fill(0);
  const g = new Array(n + 1).fill(0).map(() => []);
  for (let i = 0; i < dislikes.length; i++) {
    g[dislikes[i][0]].push(dislikes[i][1]);
    g[dislikes[i][1]].push(dislikes[i][0]);
  }
  for (let i = 1; i <= n; i++) {
    if (color[i] === 0 && !dfs(i, 1, color, g)) {
      return false;
    }
  }
  return true;
};