题目大意:
处理含限制条件的好友请求
给你一个整数 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
已经是直接朋友,那么他们之间的请求将仍然 成功 。
示例 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:
输入:n = 3, restrictions = [[0,1]], requests = [[1,2],[0,2]]
输出:[true,false]
解释:
请求 0 :用户 1 和 用户 2 可以成为朋友,所以他们成为直接朋友。
请求 1 :用户 0 和 用户 2 不能成为朋友,因为这会使 用户 0 和 用户 1 成为间接朋友 (0--2--1) 。
示例 3:
输入:n = 5, restrictions = [[0,1],[1,2],[2,3]], requests = [[0,4],[1,2],[3,1],[3,4]]
输出:[true,false,true,false]
解释:
请求 0 :用户 0 和 用户 4 可以成为朋友,所以他们成为直接朋友。
请求 1 :用户 1 和 用户 2 不能成为朋友,因为他们之间存在限制。
请求 2 :用户 3 和 用户 1 可以成为朋友,所以他们成为直接朋友。
请求 3 :用户 3 和 用户 4 不能成为朋友,因为这会使 用户 0 和 用户 1 成为间接朋友 (0--4--3--1) 。
提示:
2 <= n <= 1000
0 <= restrictions.length <= 1000
restrictions[i].length == 2
0 <= xi, yi <= n – 1
xi != yi
1 <= requests.length <= 1000
requests[j].length == 2
0 <= uj, vj <= n – 1
uj != vj
解题思路分析:
这是一道描述朋友圈的题目。在这个圈子中,朋友的敌人就是敌人,朋友的朋友还是朋友,每个圈子一定要做到团结一致,同仇敌忾!
对于这种类似划分集合类型的题目,我第一反应就是使用并查集Union-Find来解题。我们可以试想最终会划分为N个圈子,而每个圈子中都有一位大哥和一众小弟,并且大家都有相同的敌人和朋友。解题时,我们定义一个数组root[],root[i]代表i的大哥是谁。起初在没有任何人结盟的时候,每个人就是一个圈子,自己也是圈子的大哥。另外我们还需要定义两个集合,用于存储每个圈子的朋友列表和敌人列表。
我们首先开始初始化每个圈子的敌人列表,题目给出一个restrictions的二维数组。我们循环该数组,比如[1, 2]是敌对关系,那么,我们将1的敌人列表中存入2,同时将2的敌人列表中存入1。以此类推。
其次我们还需要初始化一下朋友列表,起初,每个人(圈子)的朋友只有自己。
接下来开始正式处理requests数组,即好友请求列表。首先求出双方圈子的大哥(起初大哥就是自己),如果大哥一致的话,说明大家本是一个圈子的自己人,该请求成功。如果大哥不一致时我们就要做背景调查了,我们可以使用任意一方的朋友列表去比对另外一方的敌人列表,如果一方的朋友出现在另一方的敌人列表中的话,那么对不起我们两方水火不相容,请求失败。反之如果双方没有什么恩怨,请求成功,同时,两个人成为好友实际上代表两个圈子结成一个更大的联盟。此时需要将各自的好友列表和敌人列表加入到对方的列表之中。
最后看下实现代码:
class Solution { int[] root; // 记录每个人的大哥 Map<Integer, Set<Integer>> friendMap = new HashMap<>(); // 好友列表 Map<Integer, Set<Integer>> enemyMap = new HashMap<>(); // 敌人列表 public boolean[] friendRequests(int n, int[][] restrictions, int[][] requests) { boolean[] res = new boolean[requests.length]; // 返回结果 root = new int[n]; // 初始化root数组 for(int i=0;i<n;i++) root[i] = i; // 起初没有结盟的时候,各自为一组,圈子大哥也是自己 for(int[] restriction : restrictions){ // 循环敌对关系,记录每个人的敌对关系 Set enemySet1 = enemyMap.getOrDefault(restriction[0], new HashSet<>()); enemySet1.add(restriction[1]); enemyMap.put(restriction[0], enemySet1); Set enemySet2 = enemyMap.getOrDefault(restriction[1], new HashSet<>()); enemySet2.add(restriction[0]); enemyMap.put(restriction[1], enemySet2); } for(int i=0;i<n;i++){ // 初始化好友列表,起初每个人的好友只有自己 Set<Integer> set = new HashSet<>(); set.add(i); friendMap.put(i, set); } for(int i = 0; i< requests.length; i++){ // 循环好友请求列表 int root1 = root(requests[i][0]); // 请求方的圈子大哥 int root2 = root(requests[i][1]); // 被请求方的圈子大哥 if(root1 == root2) { // 如果大哥相同,表示是自己人 res[i] = true; // 请求成功 continue; } // 双方的好友列表 Set<Integer> p1Friends = friendMap.getOrDefault(root1, new HashSet<>()); Set<Integer> p2Friends = friendMap.getOrDefault(root2, new HashSet<>()); // 双方的敌人列表 Set<Integer> p1Enemies = enemyMap.getOrDefault(root1, new HashSet<>()); Set<Integer> p2Enemies = enemyMap.getOrDefault(root2, new HashSet<>()); // 中间变量,双方是否能成为朋友 boolean canBeFriends = true; for(int p1Friend : p1Friends){ // 循环其中一方的朋友列表 if(p2Enemies.contains(p1Friend)){ // 如果另外一方的敌人列表中包含当前朋友 canBeFriends = false; // 请求失败 break; } } if(!canBeFriends){ // 如果请求失败,继续处理下一个请求 res[i] = false; continue; } // 接下来代码可以请求成功 // 合并双方的好友列表 p1Friends.addAll(p2Friends); friendMap.put(root1, p1Friends); friendMap.put(root2, p1Friends); // 合并双方的敌人列表 p1Enemies.addAll(p2Enemies); enemyMap.put(root1, p1Enemies); enemyMap.put(root2, p1Enemies); root[root1] = root2; res[i] = true; } return res; } int root(int index){ if(root[index] == index) return index; return root(root[index]); } }
本题解法执行时间为65ms。
Runtime: 65 ms, faster than 87.57% of Java online submissions for Process Restricted Friend Requests.Memory Usage: 62.2 MB, less than 10.43% of Java online submissions for Process Restricted Friend Requests.
本网站文章均为原创内容,并可随意转载,但请标明本文链接如有任何疑问可在文章底部留言。为了防止恶意评论,本博客现已开启留言审核功能。但是博主会在后台第一时间看到您的留言,并会在第一时间对您的留言进行回复!欢迎交流!
本文链接: http://leetcode.jp/leetcode-2076-process-restricted-friend-requests-解题思路分析/