写在前面:今天学了两件看似毫不相关的事——深度优先搜索(DFS)算法,和抖音推荐算法的底层原理。结果越学越发现,这两者居然有千丝万缕的联系!抖音用多模态模型把视频变成 512 维向量,再用各种算法筛选推荐——而 DFS,就是很多底层算法的"老祖宗"。
一、DFS 深度优先搜索:一条路走到黑,再回头
1.1 什么是 DFS?
老师给的定义很简洁:
"沿着一条分支一路遍历到底,回溯后再探索其余分支的图/树遍历算法。"
想象你在一个迷宫里探险:
- 你选一条路,一直往前走,直到走不通(死胡同)。
- 然后回头,回到上一个分叉口,选另一条路继续走。
- 重复这个过程,直到所有路都走过一遍。
这就是 DFS——Depth First Search,深度优先搜索。
1.2 递归实现:代码只有 8 行
function dfs(root, res = []) {
if (!root) return res; // 退出条件:走到头了
res.push(root.val); // 记录当前节点
dfs(root.left, res); // 往左走到底
dfs(root.right, res); // 往右走到底
return res;
}
这段代码做了什么?
- 退出条件:如果当前节点为空(
!root),说明走到头了,返回结果。 - 记录当前节点:把当前节点的值加入结果数组。
- 递归左子树:往左边走,重复步骤 1-3。
- 递归右子树:左边走完了,再往右边走,重复步骤 1-3。
这就像你逛商场:
- 进了一家店(
push记录)。 - 先逛左边所有分店(
dfs(root.left))。 - 左边逛完了,再逛右边所有分店(
dfs(root.right))。 - 所有店都逛完了,回家(返回结果)。
1.3 迭代实现:用栈模拟递归
递归虽然简洁,但有个问题——栈太深会爆栈。所以老师还教了迭代版本:
function dfsPreOrderIter(root) {
if (!root) return [];
const stack = [root];
const res = [];
while (stack.length) {
const node = stack.pop();
res.push(node.val);
// LIFO:先右后左,这样左子树先被处理
if (node.right) stack.push(node.right);
if (node.left) stack.push(node.left);
}
return res;
}
核心思路:用栈(Stack)代替递归调用栈。
- 栈是 LIFO(后进先出)。
- 先把根节点入栈。
- 出栈一个节点,记录它的值。
- 先把右子节点入栈,再把左子节点入栈。
- 这样下一次出栈的是左子节点——先左后右,和递归的顺序一致。
这就像你整理书桌:
- 把书一本一本叠起来(入栈)。
- 拿的时候从最上面拿(出栈)。
- 最后放上去的书,最先被拿走。
1.4 DFS 和树遍历的关系
老师还提到了一个关键联系:
"先序遍历为例:A -> B -> D -> C -> E"
二叉树的前序遍历,本质上就是 DFS。
| 遍历方式 | 顺序 | 本质 |
|---|---|---|
| 前序遍历 | 根 → 左 → 右 | DFS |
| 中序遍历 | 左 → 根 → 右 | DFS |
| 后序遍历 | 左 → 右 → 根 | DFS |
| 层序遍历 | 一层一层扫 | BFS(广度优先) |
DFS 和 BFS 是图/树遍历的两种基本策略,前序/中序/后序遍历只是 DFS 在二叉树上的三种具体实现。
二、抖音推荐算法:你在刷抖音,抖音在"刷"你
2.1 用户画像:你被打上了无数标签
老师一句话让我脊背发凉:
"我们在刷手机,手机在刷我们。"
抖音怎么"刷"你?用户画像 + 标签系统。
你每天刷的视频,会被打上各种标签:
- 唱跳、NBA、新闻、科技、美食、萌宠……
- 每天几千万用户产生的新视频数据,都会被分析。
这些标签不是简单的"有"或"没有",而是多维度向量——比如 512 维:
[
0.85, // 科技(你很感兴趣)
0.05, // 幽默(不太感兴趣)
0.03, // 西语(几乎不感兴趣)
... // 一共 512 个维度
]
每个维度代表一个兴趣标签,数值代表感兴趣的程度。 0.85 表示"非常喜欢科技类视频",0.03 表示"对西语视频无感"。
2.2 点积和余弦相似度:算你和视频的"缘分"
老师提到了两个数学概念:
- 点积操作(Dot Product):衡量两个向量的相似程度。
- 余弦相似度(Cosine Similarity):计算两个向量夹角的余弦值,越接近 1 越相似。
抖音用这些运算,算出你和每个视频的"匹配度"。 匹配度高的视频,优先推荐给你。
这就像相亲:
- 你的兴趣向量是"喜欢科技、不喜欢跳舞"。
- 视频 A 的向量是"科技类、硬核风格"→ 匹配度高 → 推荐!
- 视频 B 的向量是"跳舞类、娱乐风格"→ 匹配度低 → 不推荐。
2.3 多模态模型:视频被"拆解"成 512 维向量
老师详细讲了抖音如何把视频变成向量——多模态模型。
第一步:视觉特征提取
"逐帧提取 tensor。Vision Transformer(LLM 底层),以帧为单位去捕捉画面。"
AI 会"看"视频的每一帧:
- 能认出是一只猫、一个程序员在写代码、一个寝室围着看世界杯。
- 甚至通过画面的色彩、光影,判断视频的情绪基调——温暖治愈,还是冷酷硬核。
抖音视频数据量最大,机器学习 + 大数据训练,让 AI 越来越懂视频。
第二步:音频特征提取
"通过 ASR 技术,把配音变成文本。文本 NLP 自然语言处理,语义分析。声音大小、情绪。"
AI 还会"听"视频的声音:
- ASR(自动语音识别)把语音转成文字。
- NLP 分析文字的语义和情绪。
- 分析背景音乐的风格、节奏。
最终输出:512 维向量
视觉特征 + 音频特征,最终合并成一个 512 维的向量。这个向量就是视频的"DNA"——包含了视频的所有关键信息。
三、推荐漏斗:从 1000 万视频到 10 条推荐
3.1 第一步:召回——双塔模型广撒网
"双塔模型广撒网,千人千面。1000 万视频 → 1000 条。"
召回阶段的目标:从海量视频里,快速筛出可能感兴趣的 1000 条。
怎么做?
- 用户的兴趣向量 和 视频的向量 做点积运算。
- 计算余弦相似度,找出最相关的 1000 条。
这就像大海捞针——先拿磁铁在海边扫一扫,把含铁的东西都吸上来。
3.2 第二步:粗排——轻量模型快速筛选
"用相对轻量的机器学习模型,算一些粗的内部特征。从 1000 条筛选为 300 条。"
粗排阶段用更精细的模型,考虑更多因素:
- 视频质量、作者权重、发布时间……
- 从 1000 条进一步筛选到 300 条。
3.3 第三步:精排——预测你的行为
"预测点不点击、完播的概率、点赞、评论、分享。"
精排阶段是最核心的,用一个公式算"推荐分":
score = w1 × 点击 + w2 × 完播 + w3 × 点赞 + w4 × 评论 + w5 × 分享
w1到w5是权重,表示每个行为的重要性。- 模型预测你对每个视频的这些行为概率。
- 得分最高的视频,排在最前面。
这就像老师给你打分:平时作业 30%、期中考试 30%、期末考试 40%——加权算总分。
3.4 第四步:重排——防止你"审美疲劳"
"如果前十名都是你爱看的 AI 视频,重排机制会强制打散。每两个硬核内容,强制加入一个跳舞视频,防止产生疲劳。"
重排阶段有两个策略:
| 策略 | 说明 | 比喻 |
|---|---|---|
| Explore(探索) | 偶尔推荐一些你平时不看的类型 | 野外求生,多停留 3 秒,一个全新的兴趣标签被记录下来 |
| Exploit(利用) | 主要推荐你感兴趣的内容 | 投其所好,让你刷得停不下来 |
Explore 和 Exploit 的平衡,是推荐系统的艺术。 太 Exploit 了,你会审美疲劳;太 Explore 了,你会觉得"抖音怎么老给我推我不爱看的东西"。
这就像你吃饭:
- 天天吃你最爱吃的菜 → 吃腻了(需要 Explore)。
- 天天给你吃没见过的菜 → 你可能不喜欢(需要 Exploit)。
- 最好的方案: mostly 爱吃的 + occasionally 新尝试。
四、DFS 和推荐算法的联系:看似无关,实则相通
学到这里,我突然发现一个有趣的联系:
| DFS 算法 | 抖音推荐算法 |
|---|---|
| 沿着一条分支走到底 | 沿着一个兴趣标签深挖 |
| 回溯后探索其他分支 | Explore 机制引入新兴趣 |
| 用栈/递归实现 | 用向量运算 + 机器学习实现 |
| 遍历所有节点 | 遍历所有视频 |
推荐算法的本质,也是一种"搜索"——在海量内容中,搜索最适合你的那部分。 DFS 是计算机科学中最基础的搜索算法之一,而推荐系统则是搜索算法在工业界的"超进化版"。
五、总结:算法正在悄悄改变你的世界
| 知识点 | 说明 |
|---|---|
| DFS | 深度优先搜索,一条路走到黑再回头 |
| 递归 DFS | 代码简洁,但有爆栈风险 |
| 迭代 DFS | 用栈模拟递归,更安全 |
| 用户画像 | 用多维度向量描述用户兴趣 |
| 多模态模型 | 视觉 + 音频 → 512 维向量 |
| 余弦相似度 | 衡量用户和视频的匹配度 |
| 推荐漏斗 | 召回 → 粗排 → 精排 → 重排 |
| Explore/Exploit | 探索新内容 vs 利用已知兴趣 |
刷抖音的时候,你以为自己在选择内容,实际上算法正在选择你。 512 维向量、双塔模型、精排公式、重排机制……这些冷冰冰的算法,正在决定你每天看到什么、喜欢什么、甚至成为什么样的人。
但了解这些算法的原理,至少能让你从"被刷"变成"懂刷"——知道为什么抖音总给你推某种视频,也知道自己该如何主动探索新内容。
写在最后
今天最大的收获,是理解了推荐系统的全貌。从 DFS 这种基础算法,到抖音这种工业级推荐系统,底层逻辑都是"搜索"和"匹配"。算法本身没有好坏,关键在于怎么用。
下次面试官问你:"DFS 和 BFS 有什么区别?"
你可以淡定地说:
"DFS 是深度优先,沿着一条分支走到底再回溯,适合找路径、解迷宫;BFS 是广度优先,一层一层遍历,适合找最短路径。在二叉树中,前序/中序/后序遍历都是 DFS,层序遍历是 BFS。实际工程中,递归实现 DFS 代码简洁但可能爆栈,迭代实现用栈模拟更安全。"
然后看着面试官满意的表情,心里默念:这波,又稳了。
本文所有代码示例均来自课堂学习资料,真实可运行。