1. 程式人生 > >886. Possible Bipartition

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. 1 <= N <= 2000
  2. 0 <= dislikes.length <= 10000
  3. 1 <= dislikes[i][j] <= N
  4. dislikes[i][0] < dislikes[i][1]
  5. There does not exist i != j for which dislikes[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;
    }