持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情
题目
给定一组 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 <= 20000 <= dislikes.length <= 10^4dislikes[i].length == 21 <= dislikes[i][j] <= nai < bidislikes中每一组都 不同
思考
本题难度中等。
首先是读懂题意。给定一组 n 人(编号为 1, 2, ..., n), 把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。
一开始没有好的思路,后来参考题解,了解到可以使用染色法和深度优先搜索进行解题。也就是:
定义数组 color,数组长度为 n。规定染成颜色 A 的数字满足 color[i] = 1,染成颜色 B 的数字满足 color[i] = 2,初始化 color[i] = 0,表示该数字尚未被染色。
定义二维数组 g,g[i] 表示对于数字 i 来说不喜欢的数字的集合。
遍历数组 dislikes,判断 数字 i 和 g[i] 中的元素是否会在同一组,如果分到同一组,则返回 false。
本题的时间复杂度和空间复杂度均为 O(n + m),其中 n 题目给定的人数,m 为给定的 dislike 数组的大小。
解答
方法一:染色法、深度优先搜索
/**
* @param {number} n
* @param {number[][]} dislikes
* @return {boolean}
*/
var possibleBipartition = function(n, dislikes) {
const dfs = (curnode, nowcolor, color, g) => {
color[curnode] = nowcolor
for (const nextnode of g[curnode]) {
// nextnode 已经分组了,且和 curnode 是同一颜色
if (color[nextnode] !== 0 && color[nextnode] === color[curnode]) {
return false
}
// nextnode 未分组,nextnode 是另一种颜色(3^nowcolor)
if (color[nextnode] === 0 && !dfs(nextnode, 3 ^ nowcolor, color, g)) {
return false
}
}
return true
}
// 数组 color,规定染成颜色 A 的数字满足 color[i] = 1,染成颜色 B 的数字满足 color[i] = 2,初始化 color[i] = 0 表示该数字尚未被染色。
const color = new Array(n + 1).fill(0)
// 二维数组
const g = new Array(n + 1).fill(0).map(() => [])
for (const p of dislikes) {
g[p[0]].push(p[1])
g[p[1]].push(p[0])
}
for (let i = 1; i <= n; ++i) {
if (color[i] === 0 && !dfs(i, 1, color, g)) { // 默认颜色是1
return false
}
}
return true
}
复杂度分析:
- 时间复杂度:O(n + m),其中 n 题目给定的人数,m 为给定的 dislike 数组的大小。
- 空间复杂度:O(n + m),其中 n 题目给定的人数,m 为给定的 dislike 数组的大小。