持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
题目描述
2022/10/16 每日一题
给定一组 n 人(编号为 1, 2, ..., n), 把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。
给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和 bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false。
输入:给定总人数n和喜好数组dislikes
输出:是否可以分为两组
算法思路
从本题描述可以想到"染色",即对每个人填色,不喜欢的人不能填同一种颜色。因为在对当前元素填色的时候需要考虑所有与其冲突的元素,所以选择使用深度优先搜索算法,在对当前元素填色时,遍历所有冲突元素并判断染色是否冲突。
- 步骤:
- 首先给第一个遍历的元素上1,其冲突元素全部上2,然后依次遍历剩下的元素
- 若元素已上色就跳过
- 若元素未上色,表示此元素未与之前遍历过的元素冲突,此元素就上1色,同样对其冲突元素上2色
- 直到有颜色冲突,或者所有元素都成功上色
- 数据结构:
- 构造一个二维数组记录每个元素的冲突元素,此处使用泛型集合代替数组,因为普通数组初始化时需定义长度,而此处长度不定
- 构造一个数组记录每个元素的染色情况,0为未染色,1为染1色,2为染2色(即1的对立面)
- 定义
dfs(int i, int nowColor, int[] color, List<Integer>[] list)函数表示若当前元素i填当前颜色nowColor,是否会发生冲突 3 ^ nowColor:若nowColor为1,返回值为2,若nowColor为2,返回值为1,即用于对1,2取反
代码实现
public boolean possibleBipartition(int n, int[][] dislikes) {
int[] color = new int[n + 1];
List<Integer>[] list = new List[n + 1];
for(int i = 0; i <= n; i++){
list[i] = new ArrayList<>();
}
for(int[] dislike : dislikes){
list[dislike[0]].add(dislike[1]);
list[dislike[1]].add(dislike[0]);
}
for(int i = 1; i <= n; i++){
if(color[i] == 0 && !dfs(i, 1, color, list)){
return false;
}
}
return true;
}
public boolean dfs(int i, int nowColor, int[] color, List<Integer>[] list){
color[i] = nowColor;
for(int s : list[i]){
if(color[s] != 0 && color[s] == color[i]){
return false;
}
if(color[s] == 0 && !dfs(s, 3 ^ nowColor, color, list)){
return false;
}
}
return true;
}
补充
List<Integer>[] list = new List[n];:本质为数组,初始化时必须定义长度,使用下标[i]取数,长度为list.length
List<Integer> list = new ArrayList<>():本质为集合,初始化时无需定义长度,使用get(i)取数,长度为list.size()