这道题花了不少时间,一开始没有找对方法,以为直接遍历就完了。吃了大亏后,查了不少资料才知道要用染色(覆盖)算法来做——(有贪心算法和回溯算法两种)此处我用的是回溯算法。
class Solution {
private Map<Integer , List<Integer>> graph = new HashMap<>(); // 图存放的数据结构
private int[] color; // 每个节点的颜色
public boolean possibleBipartition(int N, int[][] dislikes) {
color = new int[N + 1];
Arrays.fill(color , - 1);
for (int i = 1;i <= N;i ++) {
graph.put(i , new ArrayList<>());
}
for (int[] edge : dislikes) { // 将图存入Map
int from = edge[0] , to = edge[1];
graph.get(from).add(to);
graph.get(to).add(from);
}
for (int i = 1;i <= N;i ++) { // 未判断的节点进行判断
if (color[i] < 0) {
color[i] = 0;
if (!dfs(i)) {
return false;
}
}
}
return true;
}
private boolean dfs(int current) {
for (int next : graph.get(current)) {
if (color[next] < 0) {
color[next] = 1 - color[current]; //第一圈为1 第二圈为0 第三圈为1 依次类推(主要是为了判断相邻的两个层会不会染色冲突)
if (!dfs(next)) { // 判断 下一节点染色是否成功 ,失败则返回false
return false;
}
} else if (color[next] == color[current]) {
return false; //发现Vi 与 Vi-1 节点颜色相同
}
}
return true;
}
}
思路:本题类似于经典的染色算法,使用DFS(深度遍历)思路解题(不知的这个的自行百度,类似走迷宫的思想),首先将限制条件转换为一个图,将color[] 赋予初始值-1,color的长度为可以使用颜色的数量。
(本做法首先要理解:题目给出的N相当于,给出了N个节点,每个节点一个颜色,所以共有N个节点,N个颜色。我们是在此前提下,判断 “不允许分组”构成的图,判断相邻的两个节点是否不同颜色)
DFS思路:
- 染色的过程是第一圈,第二圈,第三圈......以此类推进行染色判定
- 遍历所有节点的过程,对其进行染色标记,第一圈为 0 ,第二圈为 1-0,第三圈为1-(1-0)=0 , 第四圈为 1-0 其实是相邻的两圈进行判断,若Q1 = Q2 则说明在N个颜色的条件下,无法满足对限制条件图进行染色判定。
- 进行深度遍历时,若节点未进行染色判定,进行染色判定,直到到达最后一个节点,没有下一个节点时返回true,(途中染色判定失败直接返回)。
当所有节点都进行染色判定后,途中没有失败时,说明条件可以进行二分算法。