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

50 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情 >>

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

给你一个整数 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

解题思路:

1. 创建并查集;
2. 按编号添加人员;
3. 每次添加好友关系[t1,t2],遍历老死不相往来关系表restrictions,如果正好位于他们所在的两个集合,则好友关系不能建立;
4. 否则,合并这两个集合。

我的答案:

/**
 * @param {number} n
 * @param {number[][]} restrictions
 * @param {number[][]} requests
 * @return {boolean[]}
 */
var friendRequests = function(n, restrictions, requests) {
    let djSet = new DisjointSet([]);
    for (let i=0; i<n; i++) {
        djSet.add(i);
    }
    function isSafe(t1,t2) {
        let tt1 = djSet.findParent(t1);
        let tt2 = djSet.findParent(t2);
        for (let [s1,s2] of restrictions) {
            let ss1 = djSet.findParent(s1);
            let ss2 = djSet.findParent(s2);
            if ((ss1 === tt1 && ss2 === tt2) || (ss1 === tt2 && ss2 === tt1)) return false;
        }
        return true;
    }

    let res = [];
    for (let [t1,t2] of requests) {
        if ( isSafe(t1,t2) ) {
            res.push(true);
            djSet.merge(t1,t2);
        } else {
            res.push(false);
        }
    }
    return res;
};

class DisjointSet {
    constructor() {
        this.map = new Map();
    }

    findParent(v) {
        let p = this.map.get(v).parent;
        if (p === v) return v;
        // 路径压缩
        let pp = this.findParent(p);
        this.map.get(v).parent = pp;
        return pp;
    }

    add(v) {
        if (!this.map.has(v)) {
            this.map.set(v, {
                parent: v,
                rank: 1,
            });
        }
    }

    merge(v1, v2) {
        let r1 = this.findParent(v1);
        let r2 = this.findParent(v2);
        if (r1 === r2) return;
        // 按高度合并
        let rank1 = this.map.get(r1);
        let rank2 = this.map.get(r2);
        if (rank1 < rank2) {
            this.map.get(r1).parent = r2;
        } else {
            this.map.get(r2).parent = r1;
        }
        if (rank1 === rank2) {
            this.map.get(r1).rank += 1;
        }
    }
}

最后

如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )