Given a set of N
people (numbered 1, 2, ..., N
), we would like to split everyone into two groups of any size.
Each person may dislike some other people, and they should not go into the same group.
Formally, if dislikes[i] = [a, b]
, it means it is not allowed to put the people numbered a
and b
into the same group.
Return true
if and only if it is possible to split everyone into two groups in this way.
Example 1:
Input: N = 4, dislikes = [[1,2],[1,3],[2,4]] Output: true Explanation: group1 [1,4], group2 [2,3]
Example 2:
Input: N = 3, dislikes = [[1,2],[1,3],[2,3]] Output: false
Example 3:
Input: N = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]] Output: false
Note:
1 <= N <= 2000
0 <= dislikes.length <= 10000
1 <= dislikes[i][j] <= N
dislikes[i][0] < dislikes[i][1]
- There does not exist
i != j
for whichdislikes[i] == dislikes[j]
.
把N个人分为两组,其中有的人互相不喜欢,这样的不能分到一组
一开始想的比较简单,既然是分成两组,那么我就有两个set,遍历dislikes数组,尝试将第一个数字放在set1,那么第二个数字就只能放到set2
比如dislikes = [[1,2],[1,3],[2,3]]
1放到set1,2放到set2
1在set1中,所以3放到set2
2和3都在set2中,所以分不成两组
但是这样实际是存在问题的,遍历dislikes数组时,当发现两个set中都没有当前数字,那么把这个数字放到set1还是set2呢?
这个是没办法随意放的,因为这会对后面的结果产生影响。
比如dislikes = [[1,2],[3,4],[1,3]]
1放到set1,2放到set2
3放到set1,4放到set2
1和3都在set1,所以返回false
但实际上,可以把1、4放到set1,2、3放到set2
所以在决定把当前人放到哪个set时,必须把他的dislike的人也都放置完
也可以不用两个set,而是对每个人进行标识,比如把第一个人标识为1,把他dislike的人标记为-1,那么这些被标记为-1的人,他们dislike的人就都应该是1,在这个过程中如果发现想要标识的值和他已有的值不一样,返回false
整个dislikes数组相当于undirected graph的邻接表,解题就是把graph的相邻节点标识为不同颜色。
我的code如下,在solution基础上有点优化
public boolean possibleBipartition(int N, int[][] dislikes) {
HashMap<Integer, List<Integer>> map = new HashMap<>();//当前人和他dislike的人
for (int[] array : dislikes) {
List<Integer> list = map.getOrDefault(array[0], new ArrayList<>());
list.add(array[1]);
map.put(array[0], list);
list = map.getOrDefault(array[1], new ArrayList<>());
list.add(array[0]);
map.put(array[1], list);
}
int[] color = new int[N + 1];//标识
for (int i = 1; i <= N; i++) {
if (color[i] == 0 && !mark(color, i, 1, map)) {//没标记过 && 标记失败
return false;
}
}
return true;
}
private boolean mark(int[] color, int i, int c, HashMap<Integer, List<Integer>> map) {
if (color[i] == c) {//已经标记过
return true;
}
if (color[i] == -c) {
return false;
}
color[i] = c;
for (int j : map.getOrDefault(i, new ArrayList<>())) {
if (!mark(color, j, -c, map)) {
return false;
}
}
return true;
}