The "Page Recommendations II" problem involves recommending pages to users based on their friendship network and page likes. You are given two lists: one representing friendships among users, and another representing which users like which pages. For a specific user, you are asked to recommend pages that their friends like, but the user does not already like. The recommendations should not include pages the user already likes, and each recommended page should be unique.
Key constraints:
friendships
: List of pairs [user1, user2]
indicating a bidirectional friendship between user1
and user2
.page_likes
: List of pairs [user, page]
showing which user likes which page.user_id
: The user for whom you are to recommend pages.user_id
, following the above rules.The main idea is to leverage the user's social network to make personalized recommendations. At first, you might think of simply iterating through all friendships and page likes to find suitable recommendations. However, this brute-force approach can be inefficient, especially if the lists are large.
To optimize, you should:
Here is a step-by-step strategy to solve the problem efficiently:
[A, B]
, add B
to A
's friend set and A
to B
's friend set.user_id
.user_id
already likes.We use sets and hash maps because they allow for fast lookups and insertions, making the algorithm efficient even for large inputs.
Sample Input:
friendships = [[1, 2], [1, 3], [2, 4]]
page_likes = [[2, 101], [3, 101], [3, 102], [4, 103], [1, 104]]
user_id = 1
Brute-force approach:
The optimized approach is much better for large datasets because all lookups and insertions are done in constant time.
To recommend pages to a user based on their friends' likes, we build efficient mappings using hash maps and sets. This allows us to quickly gather all pages liked by friends, exclude pages the user already likes, and ensure each recommendation is unique. The approach is both efficient and elegant, leveraging basic data structures to solve a real-world recommendation problem.
def page_recommendations(friendships, page_likes, user_id):
from collections import defaultdict
# Build friendship map
friends_map = defaultdict(set)
for u, v in friendships:
friends_map[u].add(v)
friends_map[v].add(u)
# Build user to liked pages map
likes_map = defaultdict(set)
for u, page in page_likes:
likes_map[u].add(page)
# Get user's friends
friends = friends_map.get(user_id, set())
# Get pages user already likes
user_likes = likes_map.get(user_id, set())
# Gather recommendations
recommendations = set()
for friend in friends:
recommendations.update(likes_map.get(friend, set()))
# Exclude pages user already likes
recommendations -= user_likes
return list(recommendations)
#include <vector>
#include <unordered_map>
#include <unordered_set>
using namespace std;
vector<int> pageRecommendations(vector<vector<int>>& friendships, vector<vector<int>>& page_likes, int user_id) {
unordered_map<int, unordered_set<int>> friends_map;
unordered_map<int, unordered_set<int>> likes_map;
// Build friendship map
for (const auto& f : friendships) {
friends_map[f[0]].insert(f[1]);
friends_map[f[1]].insert(f[0]);
}
// Build likes map
for (const auto& l : page_likes) {
likes_map[l[0]].insert(l[1]);
}
unordered_set<int> friends = friends_map[user_id];
unordered_set<int> user_likes = likes_map[user_id];
unordered_set<int> recommendations;
for (int friend_id : friends) {
for (int page : likes_map[friend_id]) {
if (user_likes.find(page) == user_likes.end()) {
recommendations.insert(page);
}
}
}
return vector<int>(recommendations.begin(), recommendations.end());
}
import java.util.*;
public class Solution {
public List<Integer> pageRecommendations(int[][] friendships, int[][] pageLikes, int userId) {
Map<Integer, Set<Integer>> friendsMap = new HashMap<>();
Map<Integer, Set<Integer>> likesMap = new HashMap<>();
// Build friendship map
for (int[] f : friendships) {
friendsMap.computeIfAbsent(f[0], k -> new HashSet<>()).add(f[1]);
friendsMap.computeIfAbsent(f[1], k -> new HashSet<>()).add(f[0]);
}
// Build likes map
for (int[] l : pageLikes) {
likesMap.computeIfAbsent(l[0], k -> new HashSet<>()).add(l[1]);
}
Set<Integer> friends = friendsMap.getOrDefault(userId, new HashSet<>());
Set<Integer> userLikes = likesMap.getOrDefault(userId, new HashSet<>());
Set<Integer> recommendations = new HashSet<>();
for (int friendId : friends) {
for (int page : likesMap.getOrDefault(friendId, new HashSet<>())) {
if (!userLikes.contains(page)) {
recommendations.add(page);
}
}
}
return new ArrayList<>(recommendations);
}
}
function pageRecommendations(friendships, pageLikes, userId) {
const friendsMap = new Map();
const likesMap = new Map();
// Build friendship map
for (const [u, v] of friendships) {
if (!friendsMap.has(u)) friendsMap.set(u, new Set());
if (!friendsMap.has(v)) friendsMap.set(v, new Set());
friendsMap.get(u).add(v);
friendsMap.get(v).add(u);
}
// Build likes map
for (const [u, page] of pageLikes) {
if (!likesMap.has(u)) likesMap.set(u, new Set());
likesMap.get(u).add(page);
}
const friends = friendsMap.get(userId) || new Set();
const userLikes = likesMap.get(userId) || new Set();
const recommendations = new Set();
for (const friend of friends) {
const friendLikes = likesMap.get(friend) || new Set();
for (const page of friendLikes) {
if (!userLikes.has(page)) {
recommendations.add(page);
}
}
}
return Array.from(recommendations);
}