找出所有秘密的专家
[题目链接] (https://leetcode.cn/problems/find-all-people-with-secret/description/)
题目类型: 并查集
题目难度: ☀️☀️
解题思路:
利用并查集,在同一场会议的专家合并为一个集合,若是这场会议的专家均不知道秘密,就把这个集合分解。用一个secret数组表示专家是否知道秘密,即“打标签”。
以下是AC代码:
class Solution {
public:
int father[100010]; bool secret[100010];
int find(int i){
if(i != father[i]){
father[i] = find(father[i]); // 扁平化
}
return father[i];
}
void Union(int x, int y){
int fx = find(x), fy = find(y);
if(fx != fy){
father[fx] = fy;
secret[fy] = secret[fy] | secret[fx];
secret[fx] = secret[fx] | secret[fy]; // 不相等则必有一个专家知道秘密
}
}
vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
int m = meetings.size();
for(int i = 0; i < n; i++){ // 初始化
father[i] = i;
secret[i] = false;
}
father[firstPerson] = 0;
secret[0] = true; secret[firstPerson] = true;
sort(meetings.begin(), meetings.end(), [](vector<int> &a, vector<int> &b){
return a[2] < b[2];
}); // 按照会议开始的时间升序排列
for(int l = 0, r; l < m; ){
r = l;
while(r + 1 < m && meetings[r][2] == meetings[r+1][2]) // 找到开始时间相同的会议区间[l, r]
{
r++;
}
for(int i = l; i <= r; i++){
Union(meetings[i][0], meetings[i][1]);
} // 把同一时间开会的专家合并
for(int i = l; i <= r; i++){ // 同一时间开会的专家没有一个知道秘密的,分解这个集合
int a = meetings[i][0];
int b = meetings[i][1];
if(!secret[find(a)]) father[a] = a;
if(!secret[find(b)]) father[b] = b;
}
l = r + 1; // 继续寻找下一时间开始的会议
}
vector<int> ans; // 遍历一遍专家的secret数组,true即为所求
for(int i = 0; i < n; i++){
if(secret[father[i]]) ans.push_back(i);
}
return ans;
}
};