文章目录
- 1. 题目
- 2. 解题
- 2.1 DFS
- 2.2 BFS
- 2.3 并查集
1. 题目
给定一组 N 人(编号为 1, 2, …, N), 我们想把每个人分进任意大小的两组。
每个人都可能不喜欢其他人,那么他们不应该属于同一组。
形式上,如果 dislikes[i] = [a, b],表示不允许将编号为 a 和 b 的人归入同一组。
当可以用这种方法将每个人分进两组时,返回 true;否则返回 false。
示例 1:
输入:N = 4, dislikes = [[1,2],[1,3],[2,4]]
输出:true
解释:group1 [1,4], group2 [2,3]示例 2:
输入:N = 3, dislikes = [[1,2],[1,3],[2,3]]
输出:false示例 3:
输入:N = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
输出:false提示:
1 <= N <= 2000
0 <= dislikes.length <= 10000
1 <= dislikes[i][j] <= N
dislikes[i][0] < dislikes[i][1]
对于 dislikes[i] == dislikes[j] 不存在 i != j
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/possible-bipartition
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 解题
- 把人分成2组,组内没有自己不喜欢的人
2.1 DFS
着色法,初始颜色均为0,着色成1或者2,遇到矛盾的返回 false
class Solution {unordered_map<int,unordered_set<int>> m;bool ans = true;
public:bool possibleBipartition(int N, vector<vector<int>>& dislikes) {if(dislikes.size() <= 2) return true;vector<int> color(N+1, 0);for(auto& d : dislikes)//建图{m[d[0]].insert(d[1]);m[d[1]].insert(d[0]);}for(int i = 1; i <= N; i++){if(color[i] == 0)//未着色的{color[i] = 1;//着色为1dfs(i, 1, color);if(!ans)return false;}}return true;}void dfs(int id, int col, vector<int> &color){if(!ans) return;int nextcol = col==1 ? 2 : 1;//跟我相连的(不喜欢的人)颜色相反for(auto it = m[id].begin(); it != m[id].end(); it++){if(color[*it] == col)//颜色相同,出错ans = false;if(color[*it] == 0)//没有访问过的,继续着色{color[*it] = nextcol;dfs(*it, nextcol, color);}}}
};
528 ms 71.3 MB
2.2 BFS
- 思路跟dfs一样,实现形式不一样而已
class Solution {unordered_map<int,unordered_set<int>> m;
public:bool possibleBipartition(int N, vector<vector<int>>& dislikes) {if(dislikes.size() <= 2) return true;vector<int> color(N+1, 0);for(auto& d : dislikes)//建图{m[d[0]].insert(d[1]);m[d[1]].insert(d[0]);}queue<int> q;int id, col = 1, nextcol, size;for(int i = 1; i <= N; i++){if(color[i] == 0)//未访问的{color[i] = 1;//着色为1col = 1;q.push(i);while(!q.empty()){size = q.size();nextcol = col==1 ? 2 : 1;//下一层颜色需要变while(size--){id = q.front();q.pop();for(auto it = m[id].begin(); it != m[id].end(); it++){ //相连的,不喜欢的,颜色不能一样if(color[*it] == col)return false;if(color[*it] == 0){color[*it] = nextcol;//没访问的,不喜欢的,颜色跟我不一样q.push(*it);}}}col = col==1? 2 : 1;//换颜色}}}return true;}
};
524 ms 70.9 MB
2.3 并查集
- 参考 数据结构–并查集(Disjoint-Set)
类似题目:
LeetCode 684. 冗余连接(并查集)
LeetCode 990. 等式方程的可满足性(并查集)
LeetCode 959. 由斜杠划分区域(并查集)
LeetCode 1202. 交换字符串中的元素(并查集)
LeetCode 1319. 连通网络的操作次数(BFS/DFS/并查集)
程序员面试金典 - 面试题 17.07. 婴儿名字(并查集)
参考了题解区大佬们的思路
- 把并查集大小开到2倍的N,左边是自己的颜色,右边是自己不喜欢的另一种颜色
- 当a,b互斥时,a 与 b 对应的相反颜色 b+N 应该是一致的,进行
merge(a, b+N)
- 同理,
merge(b, a+N)
class dsu
{vector<int> f;
public:dsu(int n){f.resize(n+1);for(int i = 0; i < n+1; ++i)f[i] = i;}void merge(int a, int b){int fa = find(a), fb = find(b);f[fa] = fb;}int find(int a)//循环+路径压缩{int origin = a;while(a != f[a])a = f[a];return f[origin] = a;//路径压缩}
};
class Solution {
public:bool possibleBipartition(int N, vector<vector<int>>& dislikes) {if(dislikes.size() <= 2) return true;dsu u(2*N+1);int a, b, da, db;for(auto& d : dislikes){a = d[0];b = d[1];da = a+N;//a的另外一种颜色db = b+N;//b的另外一种颜色if(u.find(a) == u.find(b))return false;u.merge(a,db);//a跟b互斥,那么a跟b的反是一样的颜色u.merge(b,da);//同理}return true;}
};
256 ms 39.6 MB