
1) 【一句话结论】
基于协同过滤的简化用户行为推荐系统,通过计算用户历史课程选择的相似度(如余弦相似度),推荐相似用户喜欢的未浏览课程,核心实现包括用户-课程行为矩阵构建、相似度计算、推荐生成,时间复杂度主要取决于相似度计算步骤(如O(n²·m))。
2) 【原理/概念讲解】
老师口吻:协同过滤(Collaborative Filtering)是利用用户行为数据(如课程选择)进行推荐的核心方法,核心思想是“物以类聚,人以群分”——用户行为相似则偏好相似。本题简化为用户-用户协同过滤:
用户ID → 课程列表);交集大小 / (|用户A行为向量| × |用户B行为向量|));3) 【对比与适用场景】
| 对比维度 | 协同过滤(用户-用户) | 基于内容的推荐(物品-物品) |
|---|---|---|
| 定义 | 根据用户行为数据推荐,核心是用户相似度 | 根据物品特征(如课程标签、难度)推荐,核心是物品相似度 |
| 特性 | 依赖用户行为数据,能发现未知偏好,但冷启动问题(新用户/新课程)较严重 | 依赖物品特征,能解释推荐原因,但推荐可能同质化 |
| 使用场景 | 用户行为数据丰富(如课程选择记录多)的场景,如教育平台推荐课程 | 物品特征明确(如课程有标签、评分)的场景,或用户行为稀疏时 |
| 注意点 | 需处理数据稀疏性(用户选课少)、冷启动问题、计算复杂度高(计算所有用户对相似度) | 需准确提取物品特征,特征维度高时计算复杂,推荐可能局限于已知特征 |
4) 【示例】
伪代码(Golang风格):
// 用户-课程行为矩阵,用户ID -> 课程列表
type UserCourseMap map[int][]string
// 计算用户u和v的余弦相似度
func cosineSimilarity(u, v UserCourseMap) float64 {
vecU := make(map[string]bool)
for _, c := range u {
vecU[c] = true
}
vecV := make(map[string]bool)
for _, c := range v {
vecV[c] = true
}
common := 0
lenU := len(vecU)
lenV := len(vecV)
for c := range vecU {
if vecV[c] {
common++
}
}
if lenU == 0 || lenV == 0 {
return 0
}
return float64(common) / (float64(lenU) * float64(lenV))
}
// 推荐函数:为用户u推荐k个课程
func recommendCourses(userMap UserCourseMap, user int, k int) []string {
selectedCourses := userMap[user]
similarities := make(map[int]float64)
for otherUser, _ := range userMap {
if otherUser == user {
continue
}
sim := cosineSimilarity(userMap[otherUser], userMap[user])
similarities[otherUser] = sim
}
sortedUsers := sortUsersBySimilarity(similarities)
recommended := make(map[string]bool)
for _, otherUser := range sortedUsers {
for _, course := range userMap[otherUser] {
if !contains(selectedCourses, course) {
recommended[course] = true
}
}
}
result := make([]string, 0, len(recommended))
for course := range recommended {
result = append(result, course)
}
return result
}
func contains(list []string, course string) bool {
for _, c := range list {
if c == course {
return true
}
}
return false
}
func sortUsersBySimilarity(simMap map[int]float64) []int {
users := make([]int, 0, len(simMap))
for user, _ := range simMap {
users = append(users, user)
}
sort.Slice(users, func(i, j int) bool {
return simMap[users[i]] > simMap[users[j]]
})
return users
}
时间复杂度分析:计算所有用户对相似度时,假设有n个用户,每个用户平均有m个课程,总复杂度为O(n²·m)(每个用户需遍历其他n-1个用户,比较时遍历各自的m个课程)。实际可通过“只计算前k个相似用户”优化(k远小于n)。
5) 【面试口播版答案】
“面试官您好,我设计的这个用户行为推荐系统是基于协同过滤的简化版本,核心思路是计算用户历史课程选择的相似度,然后推荐相似用户喜欢的课程。首先,我们构建一个用户-课程行为矩阵,记录每个用户选过的课程。然后,计算任意两个用户之间的相似度,这里我用余弦相似度,把每个用户的行为看作一个向量,向量元素是课程是否被选择,相似度就是两个向量夹角的大小,夹角越小越相似。接着,对于目标用户,找出相似度最高的k个用户,汇总这些用户喜欢的课程(排除目标用户已选的),作为推荐结果。时间复杂度方面,主要步骤是计算所有用户对的相似度,假设有n个用户,每个用户平均有m个课程,那么复杂度是O(n²·m),不过实际中可以通过只计算前k个相似用户来优化。”
6) 【追问清单】
7) 【常见坑/雷区】