题目描述

(通过次数10,309 | 提交次数17,975,通过率57.35%)

朋友关系列表:Friendship
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| user1_id      | int     |
| user2_id      | int     |
+---------------+---------+
这张表的主键是 (user1_id, user2_id)。
这张表的每一行代表着 user1_id 和 user2_id 之间存在着朋友关系。

喜欢列表:Likes
+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| user_id     | int     |
| page_id     | int     |
+-------------+---------+
这张表的主键是 (user_id, page_id)。
这张表的每一行代表着 user_id 喜欢 page_id。

写一段 SQL 向user_id = 1 的用户,推荐其朋友们喜欢的页面。不要推荐该用户已经喜欢的页面。
你返回的结果中不应当包含重复项。

返回结果的格式如下例所示。
示例 1:
输入:
Friendship table:
+----------+----------+
| user1_id | user2_id |
+----------+----------+
| 1        | 2        |
| 1        | 3        |
| 1        | 4        |
| 2        | 3        |
| 2        | 4        |
| 2        | 5        |
| 6        | 1        |
+----------+----------+
Likes table:
+---------+---------+
| user_id | page_id |
+---------+---------+
| 1       | 88      |
| 2       | 23      |
| 3       | 24      |
| 4       | 56      |
| 5       | 11      |
| 6       | 33      |
| 2       | 77      |
| 3       | 77      |
| 6       | 88      |
+---------+---------+
输出:
+------------------+
| recommended_page |
+------------------+
| 23               |
| 24               |
| 56               |
| 33               |
| 77               |
+------------------+
解释:
用户1 同 用户2, 3, 4, 6 是朋友关系。
推荐页面为:页面23 来自于 用户2, 页面24 来自于 用户3, 页面56 来自于 用户3 以及 页面33 来自于 用户6。
页面77 同时被 用户2 和 用户3 推荐。
页面88 没有被推荐,因为 用户1 已经喜欢了它。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/page-recommendations
//测试数据
Create table If Not Exists Friendship (user1_id int, user2_id int);
Create table If Not Exists Likes (user_id int, page_id int);

insert into Friendship (user1_id, user2_id) values ('1', '2');
insert into Friendship (user1_id, user2_id) values ('1', '3');
insert into Friendship (user1_id, user2_id) values ('1', '4');
insert into Friendship (user1_id, user2_id) values ('2', '3');
insert into Friendship (user1_id, user2_id) values ('2', '4');
insert into Friendship (user1_id, user2_id) values ('2', '5');
insert into Friendship (user1_id, user2_id) values ('6', '1');

insert into Likes (user_id, page_id) values ('1', '88');
insert into Likes (user_id, page_id) values ('2', '23');
insert into Likes (user_id, page_id) values ('3', '24');
insert into Likes (user_id, page_id) values ('4', '56');
insert into Likes (user_id, page_id) values ('5', '11');
insert into Likes (user_id, page_id) values ('6', '33');
insert into Likes (user_id, page_id) values ('2', '77');
insert into Likes (user_id, page_id) values ('3', '77');
insert into Likes (user_id, page_id) values ('6', '88');

解题思路

根据题目要求,返回满足下列两个条件的页面:
(1)、user_id=1的用户的朋友喜欢的页面;
(2)、user_id=1的用户未标记为喜欢的页面;
对于第一个条件,我们需要先计算出user_id=1的用户的朋友是哪些。
Friendship表保存了朋友关系,因此可以从该表获取数据。不过,A与B是朋友关系,B与A同样也是朋友关系。也就是说,朋友关系是相互的。所以,可以通过如下SQL获取user_id=1的用户的朋友:

select
    distinct
    case when user1_id = 1 then user2_id else user1_id end user_id
from Friendship
where user1_id = 1
or user2_id = 1;

对于第二个条件,相当于从第一个条件过滤出的页面中,剔除已经被user_id=1的用户标记为喜欢的页面。使用NOT IN或NOT EXISTS都可以很容易的实现。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
with
tmp as (
    select
        distinct
        case when user1_id = 1 then user2_id else user1_id end user_id
    from Friendship
    where user1_id = 1
    or user2_id = 1
)
select
    distinct
    a.page_id recommended_page
from Likes a
inner join tmp b
on a.user_id = b.user_id
where not exists (
    select 1 from Likes c
    where c.user_id = 1
    and a.page_id = c.page_id);

picture loss