持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
每日刷题 2022.10.16
- leetcode原题链接:leetcode.cn/problems/po…
- 难度:中等
题目
- 给定一组 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;
};