Skip to content

There are n people in a social group labeled from 0 to n - 1. You are given an array logs where logs[i] = [timestampi, xi, yi] indicates that xi and yi will be friends at the time timestampi.

Friendship is symmetric. That means if a is friends with b, then b is friends with a. Also, person a is acquainted with a person b if a is friends with b, or a is a friend of someone acquainted with b.

Return the earliest time for which every person became acquainted with every other person. If there is no such earliest time, return -1.

Example 1:

Input: logs = [[20190101,0,1],[20190104,3,4],[20190107,2,3],[20190211,1,5],[20190224,2,4],[20190301,0,3],[20190312,1,2],[20190322,4,5]], n = 6
Output: 20190301
Explanation: 
The first event occurs at timestamp = 20190101, and after 0 and 1 become friends, we have the following friendship groups [0,1], [2], [3], [4], [5].
The second event occurs at timestamp = 20190104, and after 3 and 4 become friends, we have the following friendship groups [0,1], [2], [3,4], [5].
The third event occurs at timestamp = 20190107, and after 2 and 3 become friends, we have the following friendship groups [0,1], [2,3,4], [5].
The fourth event occurs at timestamp = 20190211, and after 1 and 5 become friends, we have the following friendship groups [0,1,5], [2,3,4].
The fifth event occurs at timestamp = 20190224, and as 2 and 4 are already friends, nothing happens.
The sixth event occurs at timestamp = 20190301, and after 0 and 3 become friends, we all become friends.

Example 2:

Input: logs = [[0,2,0],[1,0,1],[3,0,3],[4,1,2],[7,3,1]], n = 4
Output: 3
Explanation: At timestamp = 3, all the persons (i.e., 0, 1, 2, and 3) become friends.

Constraints:

  • 2 <= n <= 100
  • 1 <= logs.length <= 104
  • logs[i].length == 3
  • 0 <= timestampi <= 109
  • 0 <= xi, yi <= n - 1
  • xi != yi
  • All the values timestampi are unique.
  • All the pairs (xi, yi) occur at most one time in the input.
C++
class Solution {
public:
    int findRoot(vector<int> &parent, int x) {
        // keep find next util next is -1
        int curr = x;
        while (1) {
            int next = parent[curr];
            if (next == -1) {
                return curr;
            } else {
                curr = next;
            }
        }
    }
    static bool compare(vector<int>&v1, vector<int>&v2) {
        return v1[0] < v2[0];
    }

    int earliestAcq(vector<vector<int>> &logs, int n) {
        // init a nodes array, every time connect two parent, we firstly find root of i, and parent[root]=j
        // remove j from leaves
        // if all leaves have same root, then return time. 
        // otherwise, keep traversing logs
        sort(logs.begin(), logs.end(), compare);
        vector<int> parent(n, -1);
        set<int> leaves;
        set<int> seen;
        for (int i = 0; i < logs.size(); i++) {
            int x = logs[i][1];
            int y = logs[i][2];
            seen.insert(x);
            seen.insert(y);
            int root = findRoot(parent, x);
            // if root is itself, it is a leaf
            if(findRoot(parent,y) == root) {
                continue;
            }
            if (x == root) {
                leaves.insert(x);
            }
            parent[root] = y;
            leaves.erase(y);
            if (seen.size() == n) {
                int curr_root = findRoot(parent, 0);
                bool connected = true;
                for (auto item: leaves) {
                    if(curr_root!=findRoot(parent, item)){
                        connected=false;
                        break;
                    }
                }
                if (connected) {
                    return logs[i][0];
                }
            }
        }
        return -1;
    }
};

After optimization:

C++
#include<algorithm>
using namespace std;
class Solution {
    vector<int> parent;
    vector<int> rank;
public:
    int findRoot(int x){
        // keep find next util curr is itself
        if(parent[x]==x) {
            return x;
        } else {
            return findRoot(parent[x]);
        }
    }

    int earliestAcq(vector<vector<int>> &logs, int n) {
        // sort logs by time
        // init a parent array, every time we connect two people, we exec parent[root of i]=j
        // but we firstly check if i and j has been connected already.
            // namely find the root of j and compare it with root of i
            // if they equal, then they are connected.
        // we find root of i and parent[root]=j
        sort(logs.begin(), logs.end());
        parent.resize(n,0);
        for(int i=0;i<n;i++){
            parent[i]=i;
        }
        rank.resize(n,0);
        int groups=n;
        for(int i=0;i<logs.size();i++){
            int x=logs[i][1];
            int y=logs[i][2];
            int rootx=findRoot(x);
            int rooty=findRoot(y);
            if (rootx==rooty) {
                continue;
            }
            // At first, there are n independent person. if two root are not equal, then merge two groups
            // when only 1 group left, all people are connected
            // let node with higher rank be the parent
            if(rank[rootx]==rank[rooty]){
                parent[rootx]=rooty;
                rank[rooty]++;
            } else if(rank[rootx]<rank[rooty]){
                parent[rootx]=rooty;
            } else if(rank[rootx]>rank[rooty]) {
                parent[rooty]=rootx;
            }
            groups--;
            if(groups==1){
                return logs[i][0];
            }
        }
        // does not exist that time
        return -1;
    }
};

If rooty is root, its rank will be increased. Then it will be more likely to be parent. The graph looks like a star and the root is in the center.