leetcode
leetcode 1801 ~ 1850
处理含限制条件的好友请求

处理含限制条件的好友请求

难度:

标签:

题目描述

代码结果

运行时间: 203 ms, 内存: 17.2 MB


/* 
思路:
1. 使用并查集(Union-Find)来跟踪朋友关系。
2. 对于每个请求,检查两个用户是否可以成为朋友,即它们的根节点是否会违反任何限制。
3. 如果没有违反限制,则合并两个用户。
4. 返回请求是否成功的布尔数组。
5. 使用Java Stream API处理数组。
*/

import java.util.Arrays;
import java.util.stream.IntStream;

class Solution {
    private int[] parent;
    private int[] rank;

    public boolean[] friendRequests(int n, int[][] restrictions, int[][] requests) {
        parent = IntStream.range(0, n).toArray();
        rank = new int[n];
        Arrays.fill(rank, 1);
        return IntStream.range(0, requests.length)
                .mapToObj(i -> {
                    int u = requests[i][0];
                    int v = requests[i][1];
                    int pu = find(u);
                    int pv = find(v);
                    if (pu == pv) return true;
                    boolean canBeFriends = Arrays.stream(restrictions)
                            .noneMatch(restriction -> {
                                int r1 = find(restriction[0]);
                                int r2 = find(restriction[1]);
                                return (pu == r1 && pv == r2) || (pu == r2 && pv == r1);
                            });
                    if (canBeFriends) {
                        union(u, v);
                    }
                    return canBeFriends;
                })
                .mapToBoolean(Boolean::booleanValue)
                .toArray();
    }

    private int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    private void union(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            } else if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
        }
    }
}

解释

方法:

此题解使用了两个字典 `fri` 和 `res` 来存储朋友关系和限制条件。其中 `fri` 的键是用户编号,值是该用户的朋友集合;`res` 的键是用户编号,值是与该用户存在限制的用户集合。处理好友请求时,如果两个用户已经是直接朋友,则请求成功;如果两用户之间存在间接限制,请求失败;否则,更新双方的朋友集和限制集,并将新的朋友关系传播到相关用户,最后标记此请求为成功。

时间复杂度:

O(m * n)

空间复杂度:

O(n^2)

代码细节讲解

🦆
在算法中,如何保证当更新一个用户的朋友集和限制集后,相关联的用户集也能同步更新?
通过在更新一个用户的朋友集和限制集后,遍历该用户现有的朋友集中的每一个成员,并将每个成员的朋友集和限制集设置为更新后的集合,从而保证所有相关联用户的数据同步。这种方法虽然简单,但可能在大规模数据中效率较低,因为每次更新都需要进行广泛的遍历和更新操作。
🦆
题解中提到处理好友请求时会检查间接限制,具体是如何检查两个用户之间是否存在间接限制的?
算法通过检查两个用户各自的限制集合与对方的朋友集合是否有交集来确定是否存在间接限制。具体来说,如果用户 A 的限制集中的任何一个用户是用户 B 的朋友,或者用户 B 的限制集中的任何一个用户是用户 A 的朋友,那么就判定存在间接限制,此时好友请求失败。
🦆
题解中使用了集合合并操作来处理好友关系,这对算法的效率有什么影响?是否存在更优的数据结构来处理此类操作?
使用集合合并操作虽然直观且易于理解,但在大数据量时,每次合并操作都可能涉及大量元素的复制,这会导致效率较低。一种更优的数据结构是并查集(Union-Find),它可以更高效地处理动态连通性问题,尤其是在合并集合和查询集合的根元素时,通过路径压缩和按秩合并可以显著提升效率。
🦆
解题思路中未提及如何处理多重间接关系,例如A与B是朋友,B与C是朋友,但A与C不能是朋友的情况。算法如何解决这种复杂的间接限制?
在当前的算法实现中,这种多重间接关系的处理是通过逐步更新每个用户的限制集来实现的。当用户 A 和 B 成为朋友时,他们的限制集会合并,因此任何后续的好友请求都会检查这个更新后的限制集。如果存在如上述的复杂间接关系,算法会在合并朋友集的同时合并限制集,并在后续的请求中考虑这些合并后的限制集来判断是否能够添加新的朋友关系。这种方式确保了即使在多重间接关系的情况下也能正确处理限制。

相关问题