Skip to content

1.6 综合练习

这一节不是"刷题"。它的目标是把第一章的五种判断动作合在一起:

  • 澄清问题
  • 验证正确性
  • 判断复杂度
  • 建立模型
  • 审查工具输出

提交练习时,不只交答案,还要交你的判断过程。一个答案如果说不清为什么成立,就还不算完成。


六问法思考骨架图

在开始练习之前,先给你一张快速参考图。这张图概括了第一章最重要的思维框架——六问诊断法的完整骨架。

你可以把它作为日常工作的"清单":每次面对一个算法问题(无论是自己写还是让 AI 写),都可以按这张图的顺序检查。


六问诊断法骨架

┌─────────────────────────────────────────────────────────────────┐
│                      六问诊断法骨架图                              │
│                  (碰 AI 之前,先跑这张清单)                        │
└─────────────────────────────────────────────────────────────────┘

第一步:预测锁(写下你的初始判断,封存时间)
─────────────────────────────────────────────────────
│ 输入输出是什么?            │ 规模约束是什么?          │
│ 最简单解法是什么?          │ 我担心的边界情况?        │
─────────────────────────────────────────────────────

第一问:我真的理解问题吗?
─────────────────────────────────────────────────────
│ 产出:问题规格卡                                          │
├─────────────────────────────────────────────────────
│ 输入 │ 数据从哪里来?格式?范围?                          │
│ 输出 │ 返回什么?判断/数值/列表/安排?                    │
│ 规模 │ n 大概多少?峰值?                                 │
│ 约束 │ 时间/空间/准确率要求?                             │
│ 例子 │ 一个正常例子 + 一个边界例子                        │
─────────────────────────────────────────────────────
│ AI 角色:澄清助手(找歧义,补边界,不先写代码)             │

第二问:简单算法够用吗?
─────────────────────────────────────────────────────
│ 产出:暴力基线 + 复杂度预算                                │
├─────────────────────────────────────────────────────
│ 暴力思路 │ 最简单正确的办法是什么?                        │
│ 时间复杂度 │ O(?) 是否满足规模要求?                       │
│ 空间复杂度 │ 需要多少额外内存?                            │
│ 是否够用 │ 如果够用,可能不需要优化                        │
─────────────────────────────────────────────────────
│ AI 角色:基线助手(写基线代码,估算复杂度)                 │

第三问:有标准解法吗?
─────────────────────────────────────────────────────
│ 产出:问题类型假设                                         │
├─────────────────────────────────────────────────────
│ 类型信号 │                                                │
│   • 有对象和关系 → 图问题                                  │
│   • 找最短/最快 → 最优化问题                               │
│   • 安排/匹配/分配 → 资源分配问题                          │
│   • 序列中找规律 → 排序/查找问题                           │
│   • 判断是否出现 → 查找/去重问题                           │
│ 成立条件 │ 这个假设在什么情况下成立?                      │
│ 可能反例 │ 什么情况会让这个假设失效?                      │
─────────────────────────────────────────────────────
│ AI 角色:知识助手(列标准算法,给出建模条件)               │

第四问:能利用特殊结构吗?
─────────────────────────────────────────────────────
│ 产出:可利用结构清单                                       │
├─────────────────────────────────────────────────────
│ 常见特殊结构:                                             │
│   • 数据几乎有序 → 可能更快排序                            │
│   • 数值范围小 → 计数方法可能适用                          │
│   • 图稀疏 → 邻接表更合适                                  │
│   • 查询多更新少 → 可预处理                                │
│   • 只需近似答案 → 可能更快                                │
│   • 输入持续到达 → 数据流方法                              │
│ 对复杂度的影响:                                           │
│   每条结构 → 说明能否降低时间/空间/工程成本                 │
─────────────────────────────────────────────────────
│ AI 角色:优化助手(提出利用结构的方案)                     │

第五问:哪种范式适合?
─────────────────────────────────────────────────────
│ 产出:范式选择 + 理由                                      │
├─────────────────────────────────────────────────────
│ 范式对照表:                                               │
│   • 分治:子问题独立?合并便宜?                           │
│   • 局部选择:局部最优为何能推出全局最优?                  │
│   • 记表法:状态是什么?转移是否覆盖?                     │
│   • 试探回退:搜索空间?剪枝安全?                         │
│   • 容量分配:容量如何对应约束?                           │
│   • 随机化:允许什么错误?如何控制失败率?                  │
│   • 数据流:能保存多少状态?允许近似?                     │
│ 选择理由:必须回答范式对应的核心问题                       │
─────────────────────────────────────────────────────
│ AI 角色:证明助手(给出范式成立条件和反例)                 │

第六问:还是想不出来?
─────────────────────────────────────────────────────
│ 产出:边界说明 + 下一步行动                                │
├─────────────────────────────────────────────────────
│ 卡住时可以做:                                             │
│   • 回到第一问 → 检查问题是否定义错了                      │
│   • 放宽约束 → 先解决简化版本                              │
│   • 搜索相似问题 → 寻找标准建模                            │
│   • 请 AI/专家 → 给反例/下界/替代建模                      │
│ 边界说明:                                                 │
│   我不能解决因为... 我已排除... 我不确定... 下一步...      │
─────────────────────────────────────────────────────
│ AI 角色:替代助手(提供其他方向和参考材料)                 │

最终产出:推理收据
─────────────────────────────────────────────────────
│ 整理成一份可追溯的判断记录                                 │
├─────────────────────────────────────────────────────
│ 问题规格 │                                                │
│ 暴力基线 │                                                │
│ 类型假设 │                                                │
│ 特殊结构 │                                                │
│ 范式选择 │                                                │
│ AI 对比 │ 我 vs AI,接受/修改/拒绝理由                    │
│ 剩余风险 │ 不确定点和下一步行动                            │
─────────────────────────────────────────────────────

骨架图使用指南

这张图不是让你背下来,而是让你每次面对问题时按顺序检查

  1. 预测锁:先写下你最初的判断,哪怕可能是错的
  2. 第一问:把模糊需求变成清晰规格
  3. 第二问:找到最简单解法,判断是否够用
  4. 第三问:识别问题类型,缩小算法搜索范围
  5. 第四问:利用数据的特殊结构,可能找到更优方案
  6. 第五问:选择范式时,必须回答它的核心问题
  7. 第六问:卡住不是失败,要明确下一步做什么
  8. 推理收据:整理判断过程,留下可追溯的记录

关键原则:AI 可以参与每一层,但人必须承担问题定义和最终取舍的责任。


一页速查表

如果你需要一个更精简的版本,可以用下面这张表快速回顾:

层次核心问题产出AI 角色
预测锁我的初始判断是什么?封存的预测对照对象
第一问我真的理解问题吗?规格卡澄清助手
第二问简单算法够用吗?基线+预算基线助手
第三问有标准解法吗?类型假设知识助手
第四问能利用结构吗?结构清单优化助手
第五问哪种范式适合?范式+理由证明助手
第六问还是想不出来?边界+下一步替代助手
最终整理推理收据可追溯记录

提交格式

除非题目另有说明,每道综合题建议按下面格式提交:

text
问题规格:
- 输入:
- 输出:
- 约束:
- 边界约定:

我的判断:
- 方案:
- 正确性理由或反例:
- 时间复杂度:
- 空间复杂度:

工具协作记录:
- 我给工具的提示:
- 工具输出摘要:
- 我接受、修改或拒绝的理由:

这个格式不是为了增加文档,而是为了让你的判断能被别人检查。


基础练习

练习 1.1:任务澄清三问

把下面这个模糊任务改写成清晰规格:

帮我写一个自动分组功能。

要求回答:

  1. 输入是什么?至少列出 4 个字段。
  2. 输出是什么?是一组名单、若干小组,还是一个可解释的分组方案?
  3. 问题结构是什么?是在分配资源、匹配条件,还是排序优先级?
  4. 约束是什么?哪些条件必须满足,哪些只是尽量满足?
  5. 至少写出 3 个边界情况。

评分重点:是否把"自动分组"从一句话变成了可实现、可测试的规格。


练习 1.2:最小反例

某工具给出下面判断:

判断一个人能否参加所有会议:先按开始时间排序,然后只要每个会议的开始时间都大于前一个会议的结束时间,就说明没有冲突。

请回答:

  1. 这个思路大体在解决什么问题?
  2. "大于"一定正确吗?
  3. 如果一个会议 10:00 结束,下一个会议 10:00 开始,是否冲突?请先写出你的边界约定。
  4. 在你的边界约定下,给出一个最小反例,或者说明为什么没有反例。

评分重点:是否先确认规格,再评价代码或规则。


练习 1.3:复杂度类比

用生活场景解释下面三种增长方式,并各写一个代码形状:

增长方式生活场景代码形状
Θ(n)
Θ(n²)
Θ(log n)

要求:

  1. 生活场景要说明 n 表示什么。
  2. 代码形状不需要完整实现,但要能看出执行次数。
  3. 不能只写"一层循环/两层循环",必须解释为什么执行次数是这个量级。

进阶练习

练习 1.4:隐藏成本审查

下面代码用于去掉重复名字:

python
def remove_duplicates(names):
    result = []
    for name in names:
        if name not in result:
            result.append(name)
    return result

请回答:

  1. 表面上有几层循环?
  2. 哪一行隐藏了额外工作?
  3. 最坏情况下,隐藏工作形成什么求和式?
  4. 时间复杂度是什么?
  5. 如果改用"见过的名字记录表",时间和空间会怎样变化?

评分重点:是否能看见一行代码背后的真实工作量。


练习 1.5:建模卡

把下面需求写成建模卡:

班级要订 30 份午餐,预算 900 元以内,至少 5 位同学需要素食,尽量让大家满意。

必须包含:

  1. 输出
  2. 输入字段
  3. 硬约束
  4. 目标
  5. 规模
  6. 至少 3 个边界情况

然后写一段提示词,让工具只审查你的模型,不写代码。提示词必须要求工具检查:

  • 歧义
  • 缺失边界
  • 硬约束和目标是否混淆

练习 1.6:审查工具输出

假设你让工具根据练习 1.5 写代码。工具返回了一个方案:

先选择满意度最高的套餐,尽量多订;如果预算不够,再选择下一个满意度最高的套餐。

请审查这个方案:

  1. 它是否一定满足素食数量要求?
  2. 它是否一定满足库存限制?
  3. 它是否可能因为先选单价高的套餐,导致后面无法凑够 30 份?
  4. 构造一个小例子,让这个规则失败。
  5. 你会如何要求工具重新审查它自己的方案?

评分重点:是否能用反例攻击一个看似合理的规则。


挑战练习

练习 1.7:第一章综合任务

选择一个你熟悉的真实任务,例如:

  • 安排小组展示顺序
  • 从候选活动中选择周末计划
  • 为自习室安排座位
  • 从商品列表中找出符合条件的结果
  • 给一天的学习任务排优先级

完成以下内容:

  1. 写一张问题规格卡:输入、输出、约束、边界。
  2. 写一张建模卡:硬约束、目标、规模、表示方式。
  3. 给出一个最简单的基线方案。
  4. 分析它的时间复杂度和空间复杂度。
  5. 构造至少 3 个测试用例,其中至少 1 个是边界情况。
  6. 让工具给出一个实现或方案。
  7. 写一份审查记录:你接受、修改或拒绝了什么,理由是什么。

最终提交应包含一份简短结论:

text
我认为这个方案可以 / 不可以接受。
理由是:
1.
2.
3.
仍然不确定的是:

练习 1.8:六问法完整应用

问题:给定一个有向图,判断是否存在从一个点出发能回到自己的路径(有向环)。

要求按照六问法骨架图的完整流程进行分析:

  1. 写预测锁
  2. 写问题规格卡
  3. 给出暴力基线和复杂度预算
  4. 识别问题类型(与无向图环检测有何不同?)
  5. 列出可利用的特殊结构
  6. 选择范式并给出理由
  7. 写出边界说明和不确定点
  8. 整理成推理收据

评分重点:是否完整使用了六问法,每一问都有产出。


评分标准

维度合格表现不合格表现
问题规格输入、输出、约束、边界清楚只有一句自然语言需求
正确性能给出反例或简短理由只说"看起来对"
复杂度能说明 n 是什么,并估算增长量级只背一个 O(...)
建模区分硬约束和目标把所有要求混成一句话
工具协作能审查工具输出并说明取舍直接复制工具答案
六问法每一问都有产出,推理可追溯只说"用了六问法"但没实际产出

小结

第一章真正要训练的是判断能力。

你不需要在第一章记住很多算法名字,但你需要形成一套工作习惯:

  • 先澄清问题,再写代码。
  • 先确认规格,再验证正确性。
  • 先估复杂度,再谈性能。
  • 先建模,再让工具实现。
  • 接受或拒绝工具输出时,要说得出理由。
  • 六问法是贯穿全章的核心框架,骨架图可以作为日常速查表。

下一章会进入数据结构。重点仍然不是"背接口",而是理解不同结构适合什么约束、会带来什么代价。


上一节:1.5 建模

下一章:第2章 数据结构

新时代的算法课程