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 which dislikes[i] == dislikes[j].
方法1: dfs
花花:https://zxi.mytechroad.com/blog/graph/leetcode-886-possible-bipartition/
思路:
这个bipartite的朴素版,太慢了。主要是adjacency matrix占用了过大的空间。
class Solution {
public:
bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
vector<vector<int>> graph(N + 1, vector<int>(N + 1));
for (auto dis: dislikes) {
graph[dis[0]][dis[1]] = 1;
graph[dis[1]][dis[0]] = 1;
}
vector<int> colors(N + 1, 0);
for (int i = 1; i < N + 1; i ++) {
if (!colors[i] && !bipartiteHelper(graph, colors, i, 1)) {
return false;
}
}
return true;
}
bool bipartiteHelper(vector<vector<int>> & graph, vector<int> & colors, int i, int color){
colors[i] = color;
for (int j = 1; j < graph.size(); j++) {
if (graph[i][j]) {
if (colors[j] && colors[j] == color) return false;
if (!colors[j] && !bipartiteHelper(graph, colors, j, -color))
return false;
}
}
return true;
}
};
改进成Adjacency list, 一开始并不开(N+1) * (N + 1) 的矩阵,只将所有边push_back
class Solution {
public:
bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
vector<vector<int>> graph(N + 1);
for (auto dis: dislikes) {
graph[dis[0]].push_back(dis[1]);
graph[dis[1]].push_back(dis[0]);
}
vector<int> colors(N + 1, 0);
for (int i = 1; i < N + 1; i++) {
if (!colors[i] && !bipartiteHelper(graph, colors, i, 1)) return false;
}
return true;
}
bool bipartiteHelper(vector<vector<int>> & graph, vector<int> & colors, int i, int color) {
colors[i] = color;
for (int j : graph[i]) {
if (colors[j] == color) return false;
if (!colors[j] && !bipartiteHelper(graph, colors, j, -color)) return false;
}
return true;
}
};
方法2: bfs
思路:
方法3: Union find
grandyang: https://www.cnblogs.com/grandyang/p/10317141.html
思路:
用union find的思想来看,这道题的目的就是将所有人没有冲突的union 成两个阵营。把谁和谁进行union呢?对于i来讲,1. 他的所有敌人需要被union在一起,也就是auto j:graph[i],2. i要和每一个j的每个敌人k,union起来。这里用循环拆分,每个循环中只需要进行两次必要的检查:
- i 和 所有graph[i][j] 不能够是一个颜色,如果一样false
- 确认第一点后,assume parent1 = uf(i), parent2 = uf(j[0]),那么要将所有jk都union成parent2的颜色。
class Solution {
public:
bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
vector<vector<int>> graph(N + 1);
for (auto dis: dislikes) {
graph[dis[0]].push_back(dis[1]);
graph[dis[1]].push_back(dis[0]);
}
vector<int> root(N + 1, -1);
for (int i = 1; i < N + 1; i ++ ) root[i] = i;
for (int i = 1; i < N + 1; i++ ) {
if (graph[i].empty()) continue;
int parent1 = unionHelper(root, i);
int parent2 = unionHelper(root, graph[i][0]);
if (parent1 == parent2) return false;
for (int j: graph[i]) {
int parentj = unionHelper(root, j);
if (parentj == parent1) return false;
root[parentj] = parent2;
}
}
return true;
}
int unionHelper(vector<int> & root, int i) {
while (i != root[i]) {
root[i] = root[root[i]];
i = root[i];
}
return i;
}
};