[LeetCode] 886. Possible Bipartition

We want to split a group of n people (labeled from 1 to n) into two groups of any size. Each person may dislike some other people, and they should not go into the same group.

Given the integer n and the array dislikes where dislikes[i] = [ai, bi] indicates that the person labeled ai does not like the person labeled bi, return true 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] and 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

Constraints:

  • 1 <= n <= 2000
  • 0 <= dislikes.length <= 104
  • dislikes[i].length == 2
  • 1 <= dislikes[i][j] <= n
  • ai < bi
  • All the pairs of dislikes are unique.

可能的二分法。

给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。

给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和  bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/possible-bipartition
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意是给一个数字 N 代表有 N 个人,还有一个二维数组 dislikes,代表每两个人之间的 dislike 关系。请返回是否有可能将 N 个人分成两组。

这个题实际是在考能否将一个图的所有节点分成两组。有几种不同的思路,但是相同点都是通过染色的方式来判断是否能被二分。我这里给出一个 DFS 的做法。首先创建一个长度为 N 的额外数组,记录每个节点的涂色状况。我这里是把两组人一组设置成 1,一组设置成 -1,初始化的时候所有人都是 0。再来是通过 dislikes 里面的关系,将 input 构建成一个图,我这里是用一个邻接表记录的。

开始遍历 input,如果当前这个人是 0 的话,则开始 dfs 遍历。dfs 遍历的时候去检查,如果当前这个人 dislike 的另一个人(也就是当前这个人的邻居)已经被染成同一种颜色,则 return false;同时,如果当前的人的邻居没有被染色但是当这个邻居的邻居之间有同色的情形,也 return false。

时间O(V + E)

空间O(n^2) - 记录了graph

Java实现

 1 class Solution {
 2     public boolean possibleBipartition(int N, int[][] dislikes) {
 3         // corner case
 4         if (dislikes == null || dislikes.length == 0) {
 5             return true;
 6         }
 7 
 8         // normal case
 9         List<List<Integer>> graph = new ArrayList<>();
10         buildGraph(N, dislikes, graph);
11         // 开一个数组表示每个顶点的颜色。0表示未访问,1和-1分别表示两种颜色
12         int[] colors = new int[N];
13         for (int i = 0; i < N; i++) {
14             if (colors[i] == 0) {
15                 if (!dfs(i, graph, colors, 1)) {
16                     return false;
17                 }
18             }
19         }
20         return true;
21     }
22 
23     private void buildGraph(int N, int[][] dislikes, List<List<Integer>> graph) {
24         for (int i = 0; i < N; i++) {
25             graph.add(new ArrayList<>());
26         }
27         for (int[] d : dislikes) {
28             graph.get(d[0] - 1).add(d[1] - 1);
29             graph.get(d[1] - 1).add(d[0] - 1);
30         }
31     }
32 
33     // 从cur开始做DFS,并将cur染色为color
34     private boolean dfs(int cur, List<List<Integer>> graph, int[] colors, int color) {
35         colors[cur] = color;
36         for (int next : graph.get(cur)) {
37             // 如果发现某个邻居的颜色和自己一样,则返回false
38             if (colors[next] == color) {
39                 return false;
40             }
41             // 若发现next遍历后会发现某两个邻居染色一样,也返回false
42             if (colors[next] == 0 && !dfs(next, graph, colors, -color)) {
43                 return false;
44             }
45         }
46         return true;
47     }
48 }

 

相关题目

785. Is Graph Bipartite

886. Possible Bipartition

LeetCode 题目总结

posted @ 2020-05-28 04:45  CNoodle  阅读(121)  评论(0编辑  收藏  举报