The Leetcodify Friends Recommendations problem asks you to implement a friend recommendation system based on mutual friends. Given a list of users and their friendships, for a specific user user_id
, you need to recommend new friends. A recommended friend is someone who:
user_id
user_id
themselvesuser_id
user_id
. If two users have the same number of mutual friends, sort them by user ID in ascending order.
Constraints:
friendships
, where each pair [a, b]
means user a
and user b
are friends.
The first step is to understand the requirements for recommending friends. For a given user_id
, we need to find users who are not already friends (and not themselves), but who share at least one mutual friend with user_id
.
A brute-force approach would be to:
user_id
.To optimize, we can:
user_id
, look at their friends (i.e., friends-of-friends).Here is a step-by-step breakdown of the algorithm:
friendships
and add both directions (since friendship is bidirectional).user_id
.user_id
and not already a direct friend, increment their mutual friend count in a new hash map.We use sets for fast membership checks and hash maps for counting, making the approach efficient and clean.
Sample Input:
friendships = [[1,2], [1,3], [2,4], [3,4], [3,5], [5,6]]
user_id = 1
Step-by-Step:
[4, 5]
Brute-force Approach:
user_id
, assuming their friends also have about F friends.The Leetcodify Friends Recommendations problem is a classic example of using set operations and hash maps to efficiently find mutual connections in a social network. By building a friendship graph and focusing only on friends-of-friends, we avoid unnecessary computations and achieve an elegant, scalable solution. Sorting by mutual friend count ensures the most relevant suggestions are shown first, making the recommendation system both effective and efficient.
def recommendFriends(friendships, user_id):
from collections import defaultdict, Counter
# Build friendship graph
graph = defaultdict(set)
for a, b in friendships:
graph[a].add(b)
graph[b].add(a)
direct_friends = graph[user_id]
mutual_counts = Counter()
for friend in direct_friends:
for fof in graph[friend]:
if fof != user_id and fof not in direct_friends:
mutual_counts[fof] += 1
# Filter candidates with at least 1 mutual friend
candidates = [(cnt, uid) for uid, cnt in mutual_counts.items()]
# Sort by descending mutual friend count, then ascending user id
candidates.sort(key=lambda x: (-x[0], x[1]))
return [uid for cnt, uid in candidates]
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <algorithm>
using namespace std;
vector<int> recommendFriends(vector<vector<int>>& friendships, int user_id) {
unordered_map<int, unordered_set<int>> graph;
for (const auto& p : friendships) {
graph[p[0]].insert(p[1]);
graph[p[1]].insert(p[0]);
}
const auto& direct = graph[user_id];
unordered_map<int, int> mutual;
for (int f : direct) {
for (int fof : graph[f]) {
if (fof != user_id && direct.find(fof) == direct.end()) {
mutual[fof]++;
}
}
}
vector<pair<int,int>> candidates;
for (const auto& kv : mutual)
candidates.push_back({kv.second, kv.first});
sort(candidates.begin(), candidates.end(), [](const pair<int,int>& a, const pair<int,int>& b){
if (a.first != b.first) return a.first > b.first;
return a.second < b.second;
});
vector<int> res;
for (const auto& p : candidates) res.push_back(p.second);
return res;
}
import java.util.*;
public class Solution {
public List<Integer> recommendFriends(int[][] friendships, int user_id) {
Map<Integer, Set<Integer>> graph = new HashMap<>();
for (int[] pair : friendships) {
graph.computeIfAbsent(pair[0], k -> new HashSet<>()).add(pair[1]);
graph.computeIfAbsent(pair[1], k -> new HashSet<>()).add(pair[0]);
}
Set<Integer> direct = graph.getOrDefault(user_id, new HashSet<>());
Map<Integer, Integer> mutual = new HashMap<>();
for (int f : direct) {
for (int fof : graph.getOrDefault(f, new HashSet<>())) {
if (fof != user_id && !direct.contains(fof)) {
mutual.put(fof, mutual.getOrDefault(fof, 0) + 1);
}
}
}
List<int[]> candidates = new ArrayList<>();
for (Map.Entry<Integer, Integer> e : mutual.entrySet()) {
candidates.add(new int[]{e.getValue(), e.getKey()});
}
candidates.sort((a, b) -> b[0] != a[0] ? b[0] - a[0] : a[1] - b[1]);
List<Integer> res = new ArrayList<>();
for (int[] pair : candidates) res.add(pair[1]);
return res;
}
}
function recommendFriends(friendships, user_id) {
const graph = {};
for (const [a, b] of friendships) {
if (!graph[a]) graph[a] = new Set();
if (!graph[b]) graph[b] = new Set();
graph[a].add(b);
graph[b].add(a);
}
const direct = graph[user_id] || new Set();
const mutual = {};
for (const friend of direct) {
for (const fof of graph[friend]) {
if (fof !== user_id && !direct.has(fof)) {
mutual[fof] = (mutual[fof] || 0) + 1;
}
}
}
const candidates = [];
for (const [uid, cnt] of Object.entries(mutual)) {
candidates.push([cnt, Number(uid)]);
}
candidates.sort((a, b) => b[0] - a[0] || a[1] - b[1]);
return candidates.map(x => x[1]);
}