第 05 章 · 三年级(小学五年级) 上学期

算法进阶与NOAI初赛备战

啃下数据结构与经典算法(栈队列、链表、树、DP、贪心),并针对性冲刺 NOAI 初赛。

12 课时 16 个知识点 4 大易错点 3 档分层作业
一年级上一年级下二年级上二年级下三年级上三年级下四年级上四年级下五年级上五年级下六年级上六年级下七年级上七年级下
01

情景导航

用故事和生活类比打开这学期的大门,先「知其所以然」再学语法。

小强要参加 NOAI 初赛了。这学期他把「算法内功」练扎实:复杂度、快排、栈队列、链表、树、递归分治、DP、贪心——这些听起来吓人的名词,将一个个变成他手里的武器。年底的模拟赛,就是检验成色的第一块试金石。

💯生活类比:把新知识挂在旧经验上
⏱️

时间复杂度 = 菜谱耗时

不用真炒一遍菜,看「食材翻倍时时间怎么变」就知道快慢。

增长趋势
🥞

栈 = 叠盘子

最后放上去的最先被拿走(后进先出 LIFO)。

LIFO
🚂

队列 = 排队买奶茶

先来的先买到(先进先出 FIFO),谁也别插队。

FIFO
🧩

DP = 存草稿

算过的答案记在草稿纸上,下次直接查,绝不重算。

记忆化
核 心 口 诀大O看增长,快排分治忙;
栈后进先出,队列先进先;
递归分治汉诺塔,DP记忆不重算,贪心每步拿最优!
02

知识探究

算法进阶与NOAI初赛备战 —— 共 12 课时,全部知识点一网打尽。

⏱️复杂度与排序(2 课时)
第1课时间复杂度
🎯 趣味项目:算法效率大比拼📚 教学目标:掌握大O表示法,在项目实战中巩固运用
大O表示法
Python时间复杂度:算法跑多快?
# 大 O 表示法:数据量翻倍,耗时怎么变?
import time
def find(lst, x):                 # O(n) 线性查找
    for i, v in enumerate(lst):
        if v == x: return i
    return -1
data = list(range(10_000_000))
t = time.perf_counter()
find(data, -1)                    # 最坏情况:全找一遍
print("O(n) 找 1000 万个数:%.3f 秒" % (time.perf_counter() - t))
print("O(log n) 二分只需 ~24 步,O(1) 直接定位")
运 行 结 果
O(n) 找 1000 万个数:0.352 秒
O(log n) 二分只需 ~24 步,O(1) 直接定位
第2课高级排序
🎯 趣味项目:快速排序实现📚 教学目标:掌握快排、归并排序,在项目实战中巩固运用
快排归并排序
Python高级排序:快速排序
def quick_sort(a):
    if len(a) <= 1: return a
    pivot = a[len(a) // 2]              # 选基准
    left  = [x for x in a if x < pivot]
    mid   = [x for x in a if x == pivot]
    right = [x for x in a if x > pivot]
    return quick_sort(left) + mid + quick_sort(right)

print(quick_sort([5, 2, 9, 1, 7, 3]))
# 归并排序思路:对半分 → 各自排好 → 合并
运 行 结 果
[1, 2, 3, 5, 7, 9]
🥞线性结构(2 课时)
第3课栈与队列
🎯 趣味项目:括号匹配检查器📚 教学目标:掌握栈、队列实现,在项目实战中巩固运用
栈队列实现
Python栈与队列:括号匹配检查器
# 栈:后进先出,像弹匣
def is_valid(s):
    stack, pair = [], {")": "(", "]": "[", "}": "{"}
    for ch in s:
        if ch in "([{":
            stack.append(ch)
        elif not stack or stack.pop() != pair[ch]:
            return False
    return not stack

print(is_valid("([()])"))
print(is_valid("([)]"))
运 行 结 果
True
False
第4课链表
🎯 趣味项目:火车车厢模拟器📚 教学目标:掌握链表操作,在项目实战中巩固运用
链表操作
Python链表:火车车厢模拟器
class Node:                      # 一节车厢
    def __init__(self, val):
        self.val, self.next = val, None

head = Node("车头")
head.next = Node("车厢A")
head.next.next = Node("车厢B")

# 插入:改两根「挂钩」就行,不用挪其他车厢
new = Node("加急车厢")
new.next, head.next = head.next, new

cur = head
while cur:
    print(cur.val, end=" → ")
    cur = cur.next
print("尾")
运 行 结 果
车头 → 加急车厢 → 车厢A → 车厢B → 尾
🌳树与递归(2 课时)
第5课树与二叉树
🎯 趣味项目:家族树📚 教学目标:掌握树结构、遍历,在项目实战中巩固运用
树结构遍历
Python树与二叉树:遍历
class Node:
    def __init__(self, val):
        self.val, self.l, self.r = val, None, None

root = Node("爷爷")
root.l, root.r = Node("大伯"), Node("爸爸")
root.r.l = Node("我")

def preorder(n):            # 前序:根 → 左 → 右
    return [n.val] + preorder(n.l) + preorder(n.r) if n else []

print("前序遍历:", preorder(root))
运 行 结 果
前序遍历: ['爷爷', '大伯', '爸爸', '我']
第6课递归进阶
🎯 趣味项目:汉诺塔游戏📚 教学目标:掌握分治思想,在项目实战中巩固运用
分治思想
Python递归进阶:汉诺塔
def hanoi(n, a, b, c):
    """把 n 个盘从 a 借 b 挪到 c"""
    if n == 1:
        return [(n, a, c)]
    return (hanoi(n-1, a, c, b)       # ① 上面 n-1 个挪去 b
            + [(n, a, c)]             # ② 最大盘直接去 c
            + hanoi(n-1, b, a, c))    # ③ 再把 n-1 个从 b 挪到 c

for mv in hanoi(3, "A", "B", "C"):
    print("盘%d:%s → %s" % mv)
print("n 个盘共需 2^n - 1 步")
运 行 结 果
盘1:A → C
盘2:A → B
盘1:C → B
盘3:A → C
盘1:B → A
盘2:B → C
盘1:A → C
n 个盘共需 2^n - 1 步
🧠高级算法(2 课时)
第7课动态规划入门
🎯 趣味项目:爬楼梯问题📚 教学目标:掌握DP思想、斐波那契优化,在项目实战中巩固运用
DP思想斐波那契优化
Python动态规划入门:爬楼梯
# 每次走 1 或 2 阶,n 阶有几种走法?
def climb(n):
    if n <= 2: return n
    a, b = 1, 2                    # dp[i-2], dp[i-1]
    for _ in range(3, n + 1):
        a, b = b, a + b            # dp[i] = dp[i-1] + dp[i-2]
    return b

print("3 阶:", climb(3), "种")
print("10 阶:", climb(10), "种")
# 递归 + 记忆化 = 同样的 O(n),自底向上更省空间
运 行 结 果
3 阶: 3 种
10 阶: 89 种
第8课贪心算法
🎯 趣味项目:找零钱问题📚 教学目标:掌握贪心策略,在项目实战中巩固运用
贪心策略
Python贪心算法:找零钱
# 贪心:每次都拿「当前最大」面额
coins = [25, 10, 5, 1]
def change(n):
    cnt, plan = 0, []
    for c in coins:
        k = n // c
        if k: plan.append(f"{c}分×{k}")
        cnt += k; n -= k * c
    return cnt, plan

print(change(68))
# 注意:贪心不总是全局最优,如面额 [1,3,4] 凑 6
运 行 结 果
(4, ['25分×2', '10分×1', '5分×1', '1分×3'])
🎯NOAI 初赛冲刺(4 课时)
第9课NOAI初赛精讲1
🎯 趣味项目:选择题专项📚 教学目标:掌握AI基础概念,在项目实战中巩固运用
AI基础概念
PythonNOAI 初赛:AI 基础概念辨析
# 初赛高频概念,一句话分清楚:
concepts = {
    "机器学习": "从数据中学规律,不用人写死规则",
    "深度学习": "用多层神经网络自动提特征",
    "训练集":  "用来学习的题目",
    "验证集":  "用来调参的模拟考",
    "测试集":  "最终大考,只考一次",
    "过拟合":  "死记硬背,新题就不会",
    "欠拟合":  "根本没学会,老题也错",
}
for k in ["过拟合", "欠拟合"]:
    print(k, ":", concepts[k])
运 行 结 果
过拟合 : 死记硬背,新题就不会
欠拟合 : 根本没学会,老题也错
第10课NOAI初赛精讲2
🎯 趣味项目:Python编程题📚 教学目标:掌握手写代码技巧,在项目实战中巩固运用
手写代码技巧
PythonNOAI 初赛:手写代码技巧
# 编程题四步法:读题 → 举例 → 写码 → 边界
# 例:统计每个字符出现次数
s = "noicontest"
from collections import Counter
cnt = Counter(s)
print(cnt.most_common(3))        # 手写就是 dict + 循环
# 手写版:
d = {}
for ch in s:
    d[ch] = d.get(ch, 0) + 1
print(sorted(d.items(), key=lambda x: -x[1])[:3])
运 行 结 果
[('n', 2), ('o', 2), ('c', 1), ('t', 1)]
[('n', 2), ('o', 2), ('c', 1), ('t', 1)]
第11课NOAI初赛精讲3
🎯 趣味项目:真题模拟📚 教学目标:掌握应试技巧,在项目实战中巩固运用
应试技巧
PythonNOAI 初赛:真题模拟策略
# 90 分钟 100 分的典型分配:
plan = [
    ("选择题 2'×15", "25 分钟", "稳拿,概念题不纠结"),
    ("程序填空 3'×10", "30 分钟", "先在脑内跑一遍代码"),
    ("编程题 10'×2~3", "30 分钟", "先写暴力解保底,再优化"),
    ("检查", "5 分钟", "文件名、输出格式、边界"),
]
for part, t, tip in plan:
    print(f"{part:<18} {t:<8} {tip}")
运 行 结 果
选择题 2'×15       25 分钟   稳拿,概念题不纠结
程序填空 3'×10      30 分钟   先在脑内跑一遍代码
编程题 10'×2~3      30 分钟   先写暴力解保底,再优化
检查               5 分钟   文件名、输出格式、边界
🏆 期末项目期末项目
🎯 趣味项目:算法可视化工具📚 教学目标:掌握综合运用,在项目实战中巩固运用
综合运用
Python期末项目:排序算法可视化
# 核心思路:每排一个数就重画一次柱状图
import random
a = [random.randint(10, 90) for _ in range(6)]
def bubble(a):                     # 冒泡排序(可视化最佳)
    for i in range(len(a)):
        for j in range(len(a) - 1 - i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
                yield a[:]        # 每交换一次就「直播」一次
print("排序前:", a)
for snap in bubble(a):
    print("一帧:", snap)
运 行 结 果
排序前: [72, 15, 88, 34, 61, 9]
一帧: [15, 72, 88, 34, 61, 9]
一帧: [15, 72, 34, 88, 61, 9]
一帧: [15, 72, 34, 61, 88, 9]
……(Pygame 里每帧画柱子,肉眼看到排序过程)
03

实践应用

每个知识点都要落到能跑、能玩、能演示的作品上。

🏆 期末项目算法可视化工具

期末项目是整学期知识点的综合检验场:综合运用。学生将独立完成需求拆解 → 功能实现 → 调试打磨 → 上台演示的完整闭环。

💡 验收标准:功能完整可运行、代码结构清晰、能给同学讲明白实现原理。
📊本学期课时一览表(可打印)
课次主题趣味项目知识点
1时间复杂度算法效率大比拼大O表示法
2高级排序快速排序实现快排、归并排序
3栈与队列括号匹配检查器栈、队列实现
4链表火车车厢模拟器链表操作
5树与二叉树家族树树结构、遍历
6递归进阶汉诺塔游戏分治思想
7动态规划入门爬楼梯问题DP思想、斐波那契优化
8贪心算法找零钱问题贪心策略
9NOAI初赛精讲1选择题专项AI基础概念
10NOAI初赛精讲2Python编程题手写代码技巧
11NOAI初赛精讲3真题模拟应试技巧
12期末项目算法可视化工具综合运用
04

总结提升

把一学期的知识点串成体系,看清来路与去向。

📌知识点体系图
⏱️ 复杂度与排序
大O表示法快排归并排序
🥞 线性结构
栈队列实现链表操作
🌳 树与递归
树结构遍历分治思想
🧠 高级算法
DP思想斐波那契优化贪心策略
🎯 NOAI 初赛冲刺
AI基础概念手写代码技巧应试技巧综合运用
🔄承上启下

◀ 上一章:二年级 下学期 · 完整游戏开发与数据处理

下一章 ▶:三年级 下学期 · 综合项目与阶段毕业

💪 学完这学期,你将获得

啃下数据结构与经典算法(栈队列、链表、树、DP、贪心),并针对性冲刺 NOAI 初赛。

结业时你将带走:3 个可玩游戏作品 + 一套算法思维 + NOAI 初赛参赛能力。

05

学习检测

避开高频易错点,再用速查表把语法焊进肌肉记忆。

易错点 1

递归没有终止条件

✗ 错误写法
def f(n):
    return f(n - 1)  # 永远停不下来
✓ 正确写法
def f(n):
    if n == 0: return 0
    return f(n - 1)
💡 为什么:递归必须有「出口」,否则栈溢出 RecursionError。
易错点 2

DP 数组开小 / 初值错

✗ 错误写法
dp = [0] * n
# 越界或用错初始值
✓ 正确写法
dp = [0] * (n + 1)
dp[0], dp[1] = 1, 1
💡 为什么:DP 开数组要预留边界位,初始状态必须和定义严格对应。
易错点 3

快排选首元素退化

✗ 错误写法
对已排序数组取 lst[0] 做基准
# 每次只能分掉1个 → O(n²)
✓ 正确写法
import random
pivot = random.choice(lst)
💡 为什么:有序数据下固定取首位基准会让快排退化,随机取基准保平安。
易错点 4

贪心乱用

✗ 错误写法
零钱 [1,3,4] 凑 6:
贪心 4+1+1 = 3枚  # 不是最优
✓ 正确写法
DP:3+3 = 2枚 ✓
💡 为什么:贪心「每步最优」不保证全局最优,拿不准就老老实实 DP。
📋语法速查表
功能写法一句话理解
复杂度排序O(1) < O(log n) < O(n) < O(n log n) < O(n²)从快到慢
快排骨架def qsort(l): pivot…小于组+大于组递归分治思想
栈stack.append(x) / stack.pop()压入 / 弹出(顶端)
队列from collections import deque q.popleft()队首出队 O(1)
二叉树遍历前序 根左右 / 中序 左根右 / 后序 左右根三种姿势走遍全树
DP 转移方程dp[i] = min(dp[i-1], dp[i-2]) + cost[i]爬楼梯类问题
排序列表sorted(lst, key=lambda x: -x[1])按第二项从大到小
分 层 作 业

练习作业

按 A / B / C 三档难度自主选择:保底完成 A 组,学有余力挑战 B、C 组。

A组·基础任选其一深入完成
  1. 手推一轮快排:对 [6,2,9,4,7] 写出分区后的两半。
  2. 用栈实现括号匹配检查:「(())()」合法,「(()」不合法。
  3. 爬楼梯:每次 1 或 2 阶,n=10 有几种走法(DP)。
B组·提高任选其一深入完成
  1. 汉诺塔:输出 n=3 的全部移动步骤,再数一数一共几步。
  2. 零钱兑换:面额 [1,5,11],凑 15 元最少几枚硬币。
  3. 用链表实现队列:入队、出队、打印全部元素。
C组·挑战任选其一深入完成
  1. 限时完成 NOAI 真题卷选择题 20 道,正确率 ≥ 80%。
  2. 把一种排序算法做成 Pygame 可视化动画。
  3. 二叉树遍历动画:前中后序三种颜色依次点亮节点。