【力扣(LeetCode)】数据挖掘面试题0013:1264. 页面推荐(泛化后,基于MySQL题解)

文章大纲

      • 一、题目要求:
      • 二、模拟数据构建
      • 三、题解参考方案

【力扣(LeetCode)】数据挖掘面试题0013:1264. 页面推荐(泛化后,基于MySQL题解)_第1张图片

  • 朋友关系列表: 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。

一、题目要求:

编写解决方案,向user_id的用户,推荐其朋友们喜欢的页面。
不要推荐该用户已经喜欢的页面。以 任意顺序 返回结果,其中不应当包含重复项。

返回结果的格式如下例所示。

示例 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 已经喜欢了它。

二、模拟数据构建

Create table If Not Exists Friendship (user1_id int, user2_id int);
Create table If Not Exists Likes (user_id int, page_id int);

Truncate table Friendship;
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');

Truncate table Likes;
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');

三、题解参考方案

-- 查询每个用户的朋友喜欢但用户自己未喜欢的页面,并统计每个页面的朋友喜欢数
SELECT 
    f.user_id,        -- 用户ID
    l.page_id,        -- 页面ID
    COUNT(DISTINCT friend_id) AS friend_links  -- 喜欢该页面的朋友数量
FROM (
    -- 自连接Friendship表,构建用户与其朋友的双向关系
    SELECT user1_id AS user_id, user2_id AS friend_id FROM Friendship
    UNION ALL
    SELECT user2_id AS user_id, user1_id AS friend_id FROM Friendship
) AS f
-- 将用户的朋友与他们喜欢的页面进行连接
JOIN Likes l ON f.friend_id = l.user_id
-- 过滤条件:用户自己没有喜欢这个页面
WHERE NOT EXISTS (
    SELECT 1 
    FROM Likes my 
    WHERE my.user_id = f.user_id AND my.page_id = l.page_id
)

-- 如果子查询返回结果为空(即不存在这样的记录),则NOT EXISTS条件为真,该行数据会被保留在结果中。
-- 如果子查询返回任何结果(哪怕只是一个1),则NOT EXISTS条件为假,该行数据会被过滤掉。
	-- 与下面的LEFT JOIN写法逻辑等价
	-- LEFT JOIN Likes my 
	--   ON my.user_id = f.user_id AND my.page_id = l.page_id
	-- WHERE my.user_id IS NULL
	-- 这种写法常用于实现反连接(Anti-Join),即:
	-- "查找在 A 表中存在,但在 B 表中不存在的记录",典型场景包括:
		-- 用户未购买的商品
		-- 学生未选修的课程
		-- 员工未完成的任务

-- 按用户和页面分组,统计每个页面的朋友喜欢数
GROUP BY f.user_id, l.page_id 
-- 按用户ID升序、朋友喜欢数降序排序
ORDER BY f.user_id, friend_links DESC;

【力扣(LeetCode)】数据挖掘面试题0013:1264. 页面推荐(泛化后,基于MySQL题解)_第2张图片

你可能感兴趣的:(数据挖掘常见面试题,leetcode,数据挖掘,mysql,笔试,笔试题)