Open In App

Friendship Request Validation in a Network

Last Updated : 12 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

You have a network of individuals, each labeled with a number from 0 to n – 1. Some individuals cannot be friends due to specific rules. You also have a list of friend requests, processed one by one, the task is to determine whether each request can be accepted based on the established regulations. For each request, you need to tell the person u and v can be friends or not. If they are friends then they become friends for all future requests.

Examples:

Input: n = 3, restrictions[][] = [[0,1]], requests[][] = [[0, 2], [2, 1]]
Output: [true, false]
Explanation: Initially, no one is friends with each other.
Request 0: Person 0 and person 2 can be friends, so they become direct friends. (0–2)
Request 1: Person 2 and person 1 cannot be friends since person 0 and person 1 would be indirect friends (0–2–1).

Input: n = 5, restrictions[][] = [[0, 1], [1, 2], [2, 3]], requests[][] = [[0, 4], [1, 2], [3, 1], [3, 4]]
Output: [true, false, true, false]
Explanation: Initially, no one is friends with each other.
Request 0: Person 0 and person 4 can be friends, so they become direct friends. (0–4)
Request 1: Person 1 and person 2 cannot be friends since they are directly restricted. (1 and 2 have restrictions)
Request 2: Person 3 and Person 1 can be friends, so they become direct friends. (3–1)
Request 3: Person 3 and person 4 cannot be friends since person 0 and person 1 would be indirect friends (0–4–3–1).

Approach:

We can solve this problem Using Disjoint-Set-Union Concept .

  • Initialize two vectors, size_arr, and parent, to keep track of the size and parent of each set.
  • Implement three helper functions:
    • make_set(int v): Initialize a set for a person v, setting their parent as themselves.
    • find_set(int v): Find the representative of the set that person v belongs to, with path compression to optimize future find operations.
    • union_sets(int a, int b): Union two sets a and b, ensuring the smaller one becomes a subset of the larger one and maintaining balanced trees.
  • In the friendRequests function:
    • Initialize the parent and size_arr vectors for each person in the network.
    • Create a vector res to store the results of friend requests.
  • Iterate through each friend request in the requests vector:
    • Obtain the individuals involved in the request (u and v).
    • Find the representatives of their sets (par_u and par_v).
    • Assume the request is valid by default (flag = true).
  • Check if u and v belong to the same set (par_u and par_v are equal). If not, proceed to check if the request violates any restrictions.
  • For each restriction in the restrictions vector:
    • Obtain the individuals involved in the restriction (restr_u and restr_v).
    • Find the representatives of their sets (restr_paru and restr_parv).
    • Check if the request and restriction have the same pair of representatives, indicating a violation. If so, set flag to false and break the loop.
  • If the flag remains true (i.e., the request is valid), union the sets of u and v using the union_sets function.
  • Store the result of the request (either true for success or false for failure) in the res vector.
  • Finally, return the res vector containing the results of all friend requests.

This code effectively processes friend requests in a network while considering restrictions and ensures that friends are connected through a disjoint-set data structure with path compression for efficient operations.

Below is the implementation of the above Approach:

C++




// C++ code for the above approach:
#include <bits/stdc++.h>
using namespace std;
 
class Solution {
private:
    vector<int> sizeArr;
    vector<int> parent;
 
    // Helper function to initialize
    // a set for a person.
    void makeSet(int v)
    {
        // Initially, each person is in their
        // own set.
        parent[v] = v;
    }
 
    // Helper function to find the representative
    // of the set a person belongs to.
    int findSet(int v)
    {
 
        // If the person is the
        // representative, return their label.
        if (v == parent[v]) {
            return v;
        }
 
        // Otherwise, recursively find the
        // representative and update the parent
        // for path compression.
        parent[v] = findSet(parent[v]);
        return parent[v];
    }
 
    // Helper function to union
    // two sets, a and b.
    void unionSets(int a, int b)
    {
 
        // Find the representatives of the sets.
        a = findSet(a);
        b = findSet(b);
 
        if (a != b) {
 
            // If the sizes of sets a and b are
            // different, make the smaller one a
            // subset of the larger one.
            if (sizeArr[a] < sizeArr[b]) {
                std::swap(a, b);
            }
 
            // Set the parent of the smaller set
            // to the larger set.
            parent[b] = a;
 
            // Update the size of the larger set.
            sizeArr[a] += sizeArr[b];
        }
    }
 
public:
    vector<bool>
    friendRequests(int n,
                   vector<vector<int> >& restrictions,
                   vector<vector<int> >& requests)
    {
        sizeArr = vector<int>(n + 1);
        parent = vector<int>(n + 1);
 
        for (int i = 0; i <= n; i++) {
 
            // Initialize each person's set.
            makeSet(i);
 
            // Initially, each set has one member.
            sizeArr[i] = 1;
        }
 
        // To store the results of friend requests.
        vector<bool> res;
 
        for (auto& request : requests) {
            int u = request[0], v = request[1];
            int parU = findSet(u), parV = findSet(v);
 
            // Assume the request is
            // valid by default.
            bool flag = true;
 
            if (parU != parV) {
                for (auto& restr : restrictions) {
                    int restrU = restr[0],
                        restrV = restr[1];
                    int restrParU = findSet(restrU),
                        restrParV = findSet(restrV);
 
                    // Check if the request
                    // violates any restrictions.
                    if ((parU == restrParU
                         && parV == restrParV)
                        || (parV == restrParU
                            && parU == restrParV)) {
 
                        // The request is invalid
                        // if it violates
                        // any restriction.
                        flag = false;
                        break;
                    }
                }
                if (flag) {
 
                    // If the request is valid,
                    // union the sets of u and v.
                    unionSets(parU, parV);
                }
            }
 
            // Store the result of the request.
            res.push_back(flag);
        }
        // Return the results of all
        // friend requests.
        return res;
    }
};
 
// Drivers code
int main()
{
    int n = 5;
    vector<std::vector<int> > restrictions
        = { { 0, 1 }, { 1, 2 }, { 2, 3 } };
    vector<std::vector<int> > requests
        = { { 0, 4 }, { 1, 2 }, { 3, 1 }, { 3, 4 } };
    Solution solution;
    // Fucntion call
    vector<bool> res = solution.friendRequests(
        n, restrictions, requests);
    cout << "[";
    for (bool it : res) {
        if (it) {
            cout << "True,";
        }
        else {
            cout << "False,";
        }
    }
    cout << "]";
    return 0;
}


Java




import java.util.*;
 
public class Solution {
    private List<Integer> sizeArr, parent;
 
    // Helper function to initialize a set for a person.
    private void makeSet(int v) {
        parent.set(v, v);  // Initially, each person is in their own set.
    }
 
    // Helper function to find the representative of the set a person belongs to.
    private int findSet(int v) {
        if (v == parent.get(v)) {
            return v;  // If the person is the representative, return their label.
        }
        // Otherwise, recursively find the representative and update the parent for path compression.
        return parent.set(v, findSet(parent.get(v)));
    }
 
    // Helper function to union two sets, a and b.
    private void unionSets(int a, int b) {
        a = findSet(a);  // Find the representatives of the sets.
        b = findSet(b);
 
        if (a != b) {
            // If the sizes of sets a and b are different, make the smaller one a subset of the larger one.
            if (sizeArr.get(a) < sizeArr.get(b)) {
                int temp = a;
                a = b;
                b = temp;
            }
            parent.set(b, a);         // Set the parent of the smaller set to the larger set.
            sizeArr.set(a, sizeArr.get(a) + sizeArr.get(b)); // Update the size of the larger set.
        }
    }
 
    public List<Boolean> friendRequests(int n, List<List<Integer>> restrictions, List<List<Integer>> requests) {
        sizeArr = new ArrayList<>(n + 1);
        parent = new ArrayList<>(n + 1);
 
        for (int i = 0; i <= n; i++) {
            parent.add(i);      // Initialize each person's set.
            sizeArr.add(1);  // Initially, each set has one member.
        }
 
        List<Boolean> res = new ArrayList<>(); // To store the results of friend requests.
 
        for (List<Integer> request : requests) {
            int u = request.get(0), v = request.get(1);
            int parU = findSet(u), parV = findSet(v);
            boolean flag = true; // Assume the request is valid by default.
 
            if (parU != parV) {
                for (List<Integer> restr : restrictions) {
                    int restrU = restr.get(0), restrV = restr.get(1);
                    int restrParU = findSet(restrU), restrParV = findSet(restrV);
 
                    // Check if the request violates any restrictions.
                    if ((parU == restrParU && parV == restrParV) || (parV == restrParU && parU == restrParV)) {
                        flag = false; // The request is invalid if it violates any restriction.
                        break;
                    }
                }
                if (flag) {
                    unionSets(parU, parV); // If the request is valid, union the sets of u and v.
                }
            }
 
            res.add(flag); // Store the result of the request.
        }
 
        return res; // Return the results of all friend requests.
    }
 
    public static void main(String[] args) {
        int n = 5;
        List<List<Integer>> restrictions = Arrays.asList(Arrays.asList(0, 1), Arrays.asList(1, 2), Arrays.asList(2, 3));
        List<List<Integer>> requests = Arrays.asList(Arrays.asList(0, 4), Arrays.asList(1, 2), Arrays.asList(3, 1), Arrays.asList(3, 4));
        Solution solution = new Solution();
        List<Boolean> res = solution.friendRequests(n, restrictions, requests);
        for (boolean it : res) {
            if (it) {
                System.out.print("True ");
            } else {
                System.out.print("False ");
            }
        }
    }
}


Python




class Solution:
    def __init__(self):
        self.size_arr = []
        self.parent = []
 
    # Helper function to initialize a set for a person.
    def make_set(self, v):
        self.parent[v] = # Initially, each person is in their own set.
 
    # Helper function to find the representative of the set a person belongs to.
    def find_set(self, v):
        if v == self.parent[v]:
            return # If the person is the representative, return their label.
        # Otherwise, recursively find the representative and update the parent for path compression.
        self.parent[v] = self.find_set(self.parent[v])
        return self.parent[v]
 
    # Helper function to union two sets, a and b.
    def union_sets(self, a, b):
        a = self.find_set(a)  # Find the representatives of the sets.
        b = self.find_set(b)
 
        if a != b:
            # If the sizes of sets a and b are different, make the smaller one a subset of the larger one.
            if self.size_arr[a] < self.size_arr[b]:
                a, b = b, a
            self.parent[b] = # Set the parent of the smaller set to the larger set.
            self.size_arr[a] += self.size_arr[b]  # Update the size of the larger set.
 
    def friendRequests(self, n, restrictions, requests):
        self.size_arr = [1] * (n + 1)
        self.parent = range(n + 1)
 
        res = []  # To store the results of friend requests.
 
        # Convert restrictions to sets for faster lookup.
        restriction_set = set()
        for r in restrictions:
            restriction_set.add((r[0], r[1]))
            restriction_set.add((r[1], r[0]))
 
        for request in requests:
            u, v = request[0], request[1]
            par_u, par_v = self.find_set(u), self.find_set(v)
            flag = True  # Assume the request is valid by default.
 
            if par_u != par_v:
                if (u, v) in restriction_set:
                    flag = False
                else:
                    self.union_sets(par_u, par_v)  # If the request is valid, union the sets of u and v.
 
            res.append(flag)  # Store the result of the request.
 
        return res  # Return the results of all friend requests
 
# Test
n = 5
restrictions = [[0, 1], [1, 2], [2, 3]]
requests = [[0, 4], [1, 2], [3, 1], [3, 4]]
solution = Solution()
res = solution.friendRequests(n, restrictions, requests)
for it in res:
    if it:
        print "True",
    else:
        print "False",


C#




// C# Code addition
using System;
using System.Collections.Generic;
 
public class Solution
{
    private List<int> sizeArr, parent;
 
    // Helper function to initialize a set for a person.
    private void MakeSet(int v)
    {
        parent[v] = v;  // Initially, each person is in their own set.
    }
 
    // Helper function to find the representative of the set a person belongs to.
    private int FindSet(int v)
    {
        if (v == parent[v])
        {
            return v;  // If the person is the representative, return their label.
        }
        // Otherwise, recursively find the representative and update the parent for path compression.
        return parent[v] = FindSet(parent[v]);
    }
 
    // Helper function to union two sets, a and b.
    private void UnionSets(int a, int b)
    {
        a = FindSet(a);  // Find the representatives of the sets.
        b = FindSet(b);
 
        if (a != b)
        {
            // If the sizes of sets a and b are different, make the smaller one a subset of the larger one.
            if (sizeArr[a] < sizeArr[b])
            {
                int temp = a;
                a = b;
                b = temp;
            }
            parent[b] = a;         // Set the parent of the smaller set to the larger set.
            sizeArr[a] += sizeArr[b]; // Update the size of the larger set.
        }
    }
 
    public List<bool> FriendRequests(int n, List<List<int>> restrictions, List<List<int>> requests)
    {
        sizeArr = new List<int>(n + 1);
        parent = new List<int>(n + 1);
 
        for (int i = 0; i <= n; i++)
        {
            parent.Add(i);      // Initialize each person's set.
            sizeArr.Add(1);  // Initially, each set has one member.
        }
 
        List<bool> res = new List<bool>(); // To store the results of friend requests.
 
        foreach (List<int> request in requests)
        {
            int u = request[0], v = request[1];
            int parU = FindSet(u), parV = FindSet(v);
            bool flag = true; // Assume the request is valid by default.
 
            if (parU != parV)
            {
                foreach (List<int> restr in restrictions)
                {
                    int restrU = restr[0], restrV = restr[1];
                    int restrParU = FindSet(restrU), restrParV = FindSet(restrV);
 
                    // Check if the request violates any restrictions.
                    if ((parU == restrParU && parV == restrParV) || (parV == restrParU && parU == restrParV))
                    {
                        flag = false; // The request is invalid if it violates any restriction.
                        break;
                    }
                }
                if (flag)
                {
                    UnionSets(parU, parV); // If the request is valid, union the sets of u and v.
                }
            }
 
            res.Add(flag); // Store the result of the request.
        }
 
        return res; // Return the results of all friend requests.
    }
 
    public static void Main(string[] args)
    {
        int n = 5;
        List<List<int>> restrictions = new List<List<int>> { new List<int> { 0, 1 }, new List<int> { 1, 2 }, new List<int> { 2, 3 } };
        List<List<int>> requests = new List<List<int>> { new List<int> { 0, 4 }, new List<int> { 1, 2 }, new List<int> { 3, 1 }, new List<int> { 3, 4 } };
        Solution solution = new Solution();
        List<bool> res = solution.FriendRequests(n, restrictions, requests);
        foreach (bool it in res)
        {
            if (it)
            {
                Console.Write("True ");
            }
            else
            {
                Console.Write("False ");
            }
        }
    }
}
 
// This code is contributed by Sakshi


Javascript




class Solution {
  constructor() {
    this.sizeArr = [];
    this.parent = [];
  }
 
  // Helper function to initialize a set for a person.
  makeSet(v) {
    // Initially, each person is in their own set.
    this.parent[v] = v;
  }
 
  // Helper function to find the representative of the set a person belongs to.
  findSet(v) {
    // If the person is the representative, return their label.
    if (v === this.parent[v]) {
      return v;
    }
 
    // Otherwise, recursively find the representative and update the parent for path compression.
    this.parent[v] = this.findSet(this.parent[v]);
    return this.parent[v];
  }
 
  // Helper function to union two sets, a and b.
  unionSets(a, b) {
    // Find the representatives of the sets.
    a = this.findSet(a);
    b = this.findSet(b);
 
    if (a !== b) {
      // If the sizes of sets a and b are different, make the smaller one a subset of the larger one.
      if (this.sizeArr[a] < this.sizeArr[b]) {
        [a, b] = [b, a]; // Swap values of a and b using destructuring assignment.
      }
 
      // Set the parent of the smaller set to the larger set.
      this.parent[b] = a;
 
      // Update the size of the larger set.
      this.sizeArr[a] += this.sizeArr[b];
    }
  }
 
  friendRequests(n, restrictions, requests) {
    this.sizeArr = new Array(n + 1);
    this.parent = new Array(n + 1);
 
    for (let i = 0; i <= n; i++) {
      // Initialize each person's set.
      this.makeSet(i);
 
      // Initially, each set has one member.
      this.sizeArr[i] = 1;
    }
 
    // To store the results of friend requests.
    const res = [];
 
    for (const request of requests) {
      const u = request[0];
      const v = request[1];
      const parU = this.findSet(u);
      const parV = this.findSet(v);
 
      // Assume the request is valid by default.
      let flag = true;
 
      if (parU !== parV) {
        for (const restr of restrictions) {
          const restrU = restr[0];
          const restrV = restr[1];
          const restrParU = this.findSet(restrU);
          const restrParV = this.findSet(restrV);
 
          // Check if the request violates any restrictions.
          if (
            (parU === restrParU && parV === restrParV) ||
            (parV === restrParU && parU === restrParV)
          ) {
            // The request is invalid if it violates any restriction.
            flag = false;
            break;
          }
        }
 
        if (flag) {
          // If the request is valid, union the sets of u and v.
          this.unionSets(parU, parV);
        }
      }
 
      // Store the result of the request.
      res.push(flag);
    }
 
    // Return the results of all friend requests.
    return res;
  }
}
 
// Drivers code
const n = 5;
const restrictions = [
  [0, 1],
  [1, 2],
  [2, 3]
];
const requests = [
  [0, 4],
  [1, 2],
  [3, 1],
  [3, 4]
];
 
const solution = new Solution();
// Function call
const res = solution.friendRequests(n, restrictions, requests);
console.log("[", res.map((it) => (it ? "True" : "False")).join(","), "]");
 
// This code is contributed by shivamgupta0987654321


Output

[True,False,True,False,]




Time Complexity: O(n+m*log(n) + r*m)

  • n is the number of people in the network.
  • m is the number of friend requests.
  • r is the number of restrictions.

Auxiliary Space: O(n)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads