持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情
1、前言
每天一个算法小练习,本篇使用Java实现。
2、题目描述
给你一个整数 n,表示网络上的用户数目。每个用户按从 0 到 n - 1 进行编号。给你一个下标从 0 开始的二维整数数组 restrictions ,其中 restrictions[i] = [xi, yi] 意味着用户 xi 和用户 yi 不能成为朋友 ,不管是直接还是通过其他用户间接。
最初,用户里没有人是其他用户的朋友。给你一个下标从 0 开始的二维整数数组 requests 表示好友请求的列表,其中 requests[j] = [uj, vj] 是用户 uj 和用户 vj 之间的一条好友请求。
如果 uj 和 vj 可以成为朋友,那么好友请求将会成功。每个好友请求都会按列表中给出的顺序进行处理(即,requests[j] 会在 requests[j + 1] 前)。一旦请求成功,那么对所有未来的好友请求而言,uj 和 vj 将会成为直接朋友。
返回一个布尔数组 result ,其中元素遵循此规则:如果第 j 个好友请求 成功,那么 result[j] 就是true;否则,为false。
注意:如果 uj 和 vj 已经是直接朋友,那么他们之间的请求将仍然成功 。
2.1、示例1
输入:n = 3, restrictions = [[0,1]], requests = [[0,2],[2,1]]
输出:[true,false]
解释:
请求 0 :用户 0 和 用户 2 可以成为朋友,所以他们成为直接朋友。
请求 1 :用户 2 和 用户 1 不能成为朋友,因为这会使 用户 0 和 用户 1 成为间接朋友 (1--2--0) 。
2.2、示例2
输入:n = 3, restrictions = [[0,1]], requests = [[1,2],[0,2]]
输出:[true,false]
解释:
请求 0 :用户 1 和 用户 2 可以成为朋友,所以他们成为直接朋友。
请求 1 :用户 0 和 用户 2 不能成为朋友,因为这会使 用户 0 和 用户 1 成为间接朋友 (0--2--1) 。
3、解题思路
使用并查集维护朋友关系,每个集合内都是直接朋友或者间接朋友。对于每一条好友请求, 先假设两者可以做朋友,并连接。然后再遍历所有限制条件,如果违反就添加失败,并把并查集还原回去,否则添加好友成功;
3.1.1、实现代码
public boolean[] friendRequests(int n, int[][] restrictions, int[][] requests) {
boolean[] res = new boolean[requests.length];
// 并查集
UnionFind uf = new UnionFind(n);
for(int j = 0; j < requests.length; j++){
int u = requests[j][0], v = requests[j][1];
UnionFind cacheUF = new UnionFind(n);
cacheUF.parent = Arrays.copyOfRange(uf.parent, 0, n);
cacheUF.rank = Arrays.copyOfRange(uf.rank, 0, n);
cacheUF.size = uf.size;
// 先假设两人可以做朋友
uf.union(u, v);
boolean canSuccess = true;
for(int[] restriction: restrictions){
// 遍历全部限制来判断是否有矛盾
if(uf.isConnected(restriction[0], restriction[1])){
// 如果有矛盾则说明该请求不能实现,还原操作
uf = cacheUF;
canSuccess = false;
break;
}
}
if(canSuccess){
res[j] = true;
}
}
return res;
}
}
class UnionFind {
public int[] parent;
//每个连通区域的大小
public int[] rank;
public int size;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
for(int i = 0; i < n; i++){
parent[i] = i;
rank[i] = 1;
}
size = n;
}
public int findP(int x){
// 找到 x 的父亲节点
while(x != parent[x]){
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public void union(int x, int y) {
int rootX = findP(x);
int rootY = findP(y);
if(rootX != rootY){
// 连接
if(rank[rootX] < rank[rootY]){
parent[rootX] = rootY;
}else if(rank[rootX] > rank[rootY]){
parent[rootY] = rootX;
}else{
parent[rootX] = rootY;
rank[rootY]++;
}
size--;
}
}
public boolean isConnected(int x, int y) {
// 判断 x 和 y 是否连通
return findP(x) == findP(y);
}
public int getCount() {
return size;
}
3.1.2、执行结果
好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊