每日一学V027:从 DFS 到推荐算法:一个 AI Native 开发者的算法思维启蒙

0 阅读10分钟

从 DFS 到推荐算法:一个 AI Native 开发者的算法思维启蒙

v026 用 Canvas 在浏览器里画图、做游戏、搞数据可视化——那是"把东西画出来"的能力。

今天换个维度:从"视觉/图形"的世界走进"逻辑/算法"的世界。 学数据结构与算法——深度优先搜索(DFS)、广度优先搜索(BFS)、列表转树,以及一个真实世界级算法案例:抖音推荐系统。

为什么 AI Native 开发者要学算法?不是去 LeetCode 刷题——是因为 AI 的底层就是算法。 向量相似度是点积运算,Transformer 里有自注意力机制,推荐系统是一个多级漏斗——理解算法思维,你才能真正理解 AI 在做什么。

v025 ──→ v026 ──→ v027 今天
前端+AI   图形/视觉   算法思维
              │
   视觉世界 ──→ 逻辑世界

一、为什么要学算法?

作为 AI Native 开发者,日常是用 Claude Code 写代码、调 API、搭项目。那算法有什么用?

第一,理解 AI 的原理。 当你调用一个 LLM API 时,底层是 Transformer 架构在做矩阵运算;当你刷抖音时,背后是推荐算法在做向量相似度计算。不理解算法,你对 AI 的认知就停留在"黑盒调 API"的层面。

第二,培养结构化思维。 算法本质是"解决问题的步骤"。DFS 教你"一条路走到黑"的探索策略,BFS 教你"层层推进"的搜索策略——这些思维模式迁移到项目架构、Debug、需求分析上同样适用。

第三,面试基本功。 大厂面试必考算法,这是绕不开的现实。但今天不按 LeetCode 的套路来——我们以"理解它为什么存在"的视角来学。

先理解算法的思想,再考虑代码怎么写。思想对了,代码就是翻译。

二、DFS 深度优先搜索

什么 DFS?

Depth-First Search(深度优先搜索):沿着一条分支一路遍历到底,回溯后再探索其余分支。

想象你在走迷宫:

BFS 策略:站在入口,先看看一步范围内有哪些路,再两步、三步...
DFS 策略:选一条路,一直往前走,走不通了退回来,换另一条路
        [1]
       /   \
    [2]     [5]
   /   \      \
 [3]   [4]    [6]

DFS 遍历顺序:123456
(一路向左走到底,回溯,再向右)

BFS 遍历顺序:125346
(一层一层往下扫)

递归实现(最简单的方式)

function dfs(root, res = []) {
    if (!root) return res        // 退出条件:到叶子节点了
    res.push(root.val)           // 处理当前节点
    dfs(root.left, res)          // 递归左子树——"一条路走到底"
    dfs(root.right, res)         // 回溯后,递归右子树
    return res
}

递归版的 DFS 就是三步:处理当前 → 递归左边 → 递归右边。 代码极简,但背后是函数调用栈在帮你记住"回溯点"。

递归的核心: 函数自己调用自己,每次调用都会在调用栈上压入一个新的执行上下文。当递归到叶子节点(!root),开始逐层返回——这就是"回溯"的本质。

迭代实现(手写栈)

递归虽简洁,但理解"栈"这个数据结构才能掌握 DFS 的本质:

// 递归的升级版:迭代实现
function dfsPreOrderIter(root) {
    if (!root) return []
    const res = []
    const stack = [root]          // 用栈模拟递归
    while (stack.length) {
        const node = stack.pop()  // 弹出栈顶——LIFO 后进先出
        res.push(node.val)
        // 先右后左——这样左会先出栈
        if (node.right) stack.push(node.right)
        if (node.left) stack.push(node.left)
    }
    return res
}
栈的工作原理:后进先出(LIFO)

push(1):  [1]
push(2):  [1, 2]
push(3):  [1, 2, 3]
pop():    3 ← 最后进去的,最先出来
pop():    2
pop():    1

递归版和迭代版的本质是一样的——都是在用栈。 递归用的是 JS 引擎的调用栈(你不可见),迭代版用的是手动维护的数组栈(你完全可控)。

什么时候用迭代? 当树的深度可能超过调用栈限制(约 10000 层),递归会导致栈溢出。这时必须用迭代。

三、BFS 广度优先搜索

什么是 BFS?

Breadth-First Search(广度优先搜索):从根节点开始,一层一层地遍历。先访问距离近的节点,再访问距离远的节点。

function bfs(root) {
    if (!root) return []
    const res = []
    const queue = [root]          // 用队列——不是栈!
    while (queue.length) {
        const node = queue.shift() // 从队头取出——FIFO 先进先出
        res.push(node.val)
        if (node.left) queue.push(node.left)
        if (node.right) queue.push(node.right)
    }
    return res
}

DFS 用栈(pop/push),BFS 用队列(shift/push)。 数据结构不同,遍历逻辑完全不同:

DFS:  栈 = 后进先出 = 一条路走到底再回头
BFS: 队列 = 先进先出 = 一层一层往外扩
         [1]          ← 第 0 层
       /     \
    [2]       [3]     ← 第 1 层
   /   \     /   \
 [4]   [5] [6]   [7]  ← 第 2 层

BFS 遍历:1 → 2 → 3 → 4 → 5 → 6 → 7

队列变化过程:
初始: [(1)]
取出1,放入2,3: [(2), (3)]
取出2,放入4,5: [(3), (4), (5)]
取出3,放入6,7: [(4), (5), (6), (7)]
...依次取出 4,5,6,7

DFS vs BFS:什么时候用哪个?

DFSBFS
数据结构栈(Stack)队列(Queue)
遍历方式深度优先——一条路到底广度优先——一层层扫
空间复杂度O(h),h=树的高度O(w),w=树的最大宽度
适用场景路径探索、回溯问题、连通性最短路径、层级遍历、社交关系
代码特点递归简洁,迭代需手动栈只能用队列,没有简洁递归写法

直观判断法:

  • 要找"最短路径"、"第几层" → BFS
  • 要"探索所有可能"、"路径是否存在" → DFS
  • 树很深但很窄 → DFS(省空间)
  • 树很宽但很浅 → BFS(省空间)

四、列表转树:DFS 的实际应用

前端开发中有一个高频场景:后端返回扁平数组,你需要转成树形结构渲染。

// 后端返回的扁平数据
const list = [
    { id: 1, pid: null, name: '根节点' },
    { id: 2, pid: 1,    name: '子节点A' },
    { id: 3, pid: 1,    name: '子节点B' },
    { id: 4, pid: 2,    name: '叶子A-1' },
]

// 你需要渲染的树形结构
const tree = [
    {
        id: 1, name: '根节点',
        children: [
            { id: 2, name: '子节点A', children: [{ id: 4, ... }] },
            { id: 3, name: '子节点B', children: [] },
        ]
    }
]

这就是 DFS 的典型应用——先建好 Map 索引,再递归(或遍历)构建父子关系。 核心思路:

  1. 遍历一遍 list,把所有节点放进 Map<id, node>
  2. 再遍历一遍,根据 pid 把每个节点挂到父节点的 children
  3. 返回 pid === null 的节点(根节点)

这是一个 O(n) 的两遍扫描,不需要嵌套循环。

五、真实世界的算法:抖音推荐系统

DFS 和 BFS 是基础算法。现在来看一个工业级算法系统——它就在你每天刷的短视频里。

你在刷抖音时,抖音在干嘛?

"我们在刷手机,手机在刷我们。"

你每滑动一次、点赞一次、停留多一秒——都在为你的用户画像贡献数据。

用户画像
┌────────────────────────────────────┐
 tag: 科技 0.85                     
 tag: 幽默 0.05                     
 tag: 西语 0.03                     
 还有 509 个维度...                  
└────────────────────────────────────┘

你的画像 = 一个 512 维的向量
视频的特征 = 也是一个 512 维的向量

相似度 = cosine(你的向量, 视频向量)
结果越接近 1  你们越"像"  推荐给你

这就是你刷到的每个视频背后的数学——向量点积(cosine 相似度)。 每天几千万用户 × 几千万视频的向量之间做海量计算,这就是抖音后台的算力在做的事。

第一步:多模态解构

一段视频上传到抖音,首先被拆解为:

一段 15 秒视频
    │
    ├── 视觉特征(逐帧提取)
    │   Vision Transformer 逐帧分析
    │   认出:一只猫 / 程序员写代码 / 寝室看世界杯
    │   判断情绪基调:温柔治愈 / 冷酷硬核
    │   → 数据量最大的一维
    │
    ├── 音频特征
    │   ASR 技术:语音 → 文本
    │   NLP 分析:关键词、语义
    │   音量、情绪
    │
    └── → 汇总为一个 512 维向量

这个向量 = 视频的"数字指纹"

多模态是 LLM 的主要发展方向。 一段视频 = 视觉 + 音频 + 文本,每个维度用不同的 AI 模型处理,最终融合成一个统一的向量表示。

第二步:推荐漏斗

输入:每个视频 512 维向量。输出:你屏幕上那一条视频。

1000 万条视频
    
      召回:双塔模型
      向量点积运算,cosine 夹角
       1000 万筛选出 1000 
    
1000 
    
      粗排:轻量 ML 模型
      计算内部特征
       1000 条筛选到 300 
    
300 
    
      精排:深度模型
      score = w₁·点击 + w₂·完播 + w₃·点赞 + w₄·评论 + w₅·分享
      预测你每一项行为的概率,加权算总分
    
    
      重排:打散策略
      前十名都是 AI 视频?强制插入一条跳舞视频
      防止内容疲劳
    
    
你屏幕上看到的那一条

这个漏斗的关键设计:

阶段数据量模型复杂度目标
召回1000万→1000向量点积(轻量)快速缩小范围
粗排1000→300轻量 ML再筛一遍
精排300→排序深度模型精确预测你的行为
重排最终列表规则策略防疲劳 + 探索

Explore & Exploit:探索与利用

最精妙的设计在重排阶段:

80% Exploit(利用)
  → 给你看已知你爱看的

20% Explore(探索)
  → 给你看你不确定爱不爱看的

如果你在"野外求生"视频上多停留了几秒...
  → 一个全新的兴趣标签被写入你的用户画像
  → 下次推荐就有了新内容来源

这 20% 的探索机制决定了:不是你主动搜索才看到新东西,而是算法在试探你的潜在兴趣。 你的每一次"莫名多看了几秒",都在重新定义你是谁。

从算法视角看推荐系统

回到 DFS 和 BFS——推荐系统跟它们有关系吗?

DFS 的"回溯"思想 → 探索(Explore):在你熟悉的主路径之外,
                   开辟新分支,看看有没有新的兴趣点

BFS 的"层级"思想 → 漏斗结构:从 1000 万 → 1000300 → 排序
                   层层过滤,每层用不同策略

基础算法 + 基础数据结构 = 工业级系统的种子。 向量是数组,漏斗是队列,用户画像是 Map——你刚学的基础数据结构,在工业系统中以更复杂的形式复用着。

结语

今天从基础算法到工业系统,走完了一条"算法思维升级链":

  1. 为什么要学算法 —— 理解 AI 底层原理、培养结构化思维、面试基本功。不刷题,先理解思想
  2. DFS 深度优先搜索 —— 递归版(调用栈自动回溯)+ 迭代版(手写栈,后进先出)。适合路径探索、连通性问题
  3. BFS 广度优先搜索 —— 队列实现(先进先出),一层一层往外扩。适合最短路径、层级遍历
  4. 列表转树 —— DFS 在前端开发中的实际应用,Map + 两遍扫描 = O(n)
  5. 抖音推荐系统 —— 多模态解构 → 512 维向量 → 推荐漏斗(召回→粗排→精排→重排)→ Explore & Exploit。你刷的不是视频,是数学

从 v026 到今天的 AI 全栈版图扩展:

视觉线               算法线
│                    │
├── v026: Canvas 2D  ├── v027: 算法思维 ← 今天新增!
│   图形编程         │    DFS/BFS/推荐系统
│                    │
│  "把东西画出来""理解系统怎么运作"
│                    │
└────────────────────┴─────────────────────────

v026 让你能用 Canvas 画图做游戏——那是"手"的能力。今天让你理解算法和推荐系统——这是"脑"的能力。 手脑并用,才是完整的 AI Native 开发者。

AI 的底层是数学,AI 的工程是代码,AI 的产品是推荐给你的那条视频。 从写 dfs() 函数到理解抖音的推荐漏斗——算法思维贯穿始终。

下篇见。