886. Possible Bipartition
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;
}