1. 项目背景与核心价值
这个OJ打卡项目源于计算机考研复试的实战需求。东华大学计算机专业研究生复试历来重视算法能力考核,上机编程题占总分30%以上。去年上岸的学长分享经验时特别强调:"复试前三个月必须保持每日3题的训练强度,否则考场看到红黑树和动态规划直接懵圈。"
我作为跨考生,从去年12月开始在NowCoder和LeetCode双平台刷题,但很快发现三个致命问题:第一,随机选题导致知识点覆盖不全;第二,缺乏系统复盘容易遗忘;第三,没有进度追踪难以坚持。于是今年1月着手搭建这个OJ特训体系,核心解决三个痛点:
- 针对性训练 - 按东华历年真题频度排序题库(字符串处理>树结构>动态规划)
- 结构化复盘 - 每道题记录解题思路、时间复杂度和易错点
- 可视化追踪 - GitHub仓库用甘特图记录每日完成情况
2. 训练体系设计
2.1 题库筛选标准
从三个维度构建专属题库(当前已积累237题):
| 维度 | 权重 | 筛选依据 | 示例题目 |
|---|---|---|---|
| 东华真题复现 | 40% | 2018-2023年机试原题 | 字符串压缩(2022年第3题) |
| 核心算法覆盖 | 30% | 《算法导论》重点章节 | 红黑树插入操作 |
| 高频企业题 | 30% | 腾讯/字节跳动近2年面试高频题 | LRU缓存机制 |
2.2 每日训练流程
我的黄金三小时训练法(实测正确率提升65%):
-
限时模拟(90分钟)
- 设置IDE全屏模式强制专注
- 使用CPP Timer插件严格计时(Easy题15min/Medium题25min/Hard题40min)
- 必须通过所有测试用例才记录完成
-
错题分析(60分钟)
- 对未AC的题目用二叉树法分析:
text复制
根节点 → 错误类型(WA/TLE/RE) ├─左子树 → 测试用例分析(边界条件?) └─右子树 → 算法选择(贪心是否最优?)
- 对未AC的题目用二叉树法分析:
-
代码重构(30分钟)
- 至少用两种解法重新实现(如递归改迭代)
- 对比不同语言性能差异(C++ vs Python)
3. 7~9日真题复盘
3.1 Day7:红黑树节点删除(2021年压轴题)
原题要求:实现红黑树删除后的修复逻辑(CLRS 13.4节)
cpp复制void RB_Delete_Fixup(Node* x, Node* root) {
while (x != root && x->color == BLACK) {
if (x == x->parent->left) {
Node* w = x->parent->right; // 兄弟节点
if (w->color == RED) { // Case 1
w->color = BLACK;
x->parent->color = RED;
Left_Rotate(x->parent);
w = x->parent->right;
}
// 继续处理Case 2-4...
}
}
x->color = BLACK;
}
踩坑记录:
- 指针未判空导致段错误(需添加
if(w == NIL) return) - Case3到Case4转换时忘记更新兄弟节点
- 测试用例:连续删除根节点后树结构验证
3.2 Day8:地铁换乘规划(动态规划变种)
题目变形:在传统Floyd算法基础上增加换乘惩罚系数
python复制def metro_plan(n, graph, transfer_penalty):
dist = [[float('inf')] * n for _ in range(n)]
for i in range(n):
for j in range(n):
dist[i][j] = graph[i][j]
if i != j and dist[i][j] != float('inf'):
dist[i][j] += transfer_penalty # 换乘代价
for k in range(n):
for i in range(n):
for j in range(n):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return dist
性能优化:
- 使用numba加速三重循环(耗时从3.2s→0.4s)
- 稀疏矩阵改用COO存储格式(内存占用减少72%)
3.3 Day9:JSON解析器(栈状态机实现)
核心状态转移表:
| 当前状态 | 遇到"{" | 遇到"}" | 遇到":" | 遇到"," |
|---|---|---|---|---|
| START | OBJECT | ERROR | ERROR | ERROR |
| OBJECT | NESTED | END | KEY | ERROR |
| KEY | ERROR | ERROR | VALUE | ERROR |
| VALUE | OBJECT | POP | ERROR | KEY |
内存管理技巧:
- 使用string_view避免子串拷贝
- 预分配token缓冲区(减少vector扩容开销)
4. 效率提升方法论
4.1 调试技巧三板斧
-
防御性编程:
- 所有指针解引用前assert校验
- 输入参数范围检查(如
if(n > 1e6) throw...)
-
可视化调试:
- 树结构用Graphviz生成图片
bash复制echo "digraph G { A -> B; B -> C; }" | dot -Tpng > tree.png -
压力测试:
- 用Python生成极限数据
python复制import random print(10**6) print(' '.join(str(random.randint(1,1e9)) for _ in range(10**6)))
4.2 时间管理策略
我的番茄钟改良方案:
- 编码阶段:25分钟专注+5分钟静态检查(Clang-Tidy)
- 调试阶段:15分钟单步调试+5分钟写测试用例
- 每日最后20分钟录制讲解视频(强化记忆)
5. 常见问题解决方案
5.1 递归爆栈问题
场景:二叉树直径计算(深度可能超过1e4)
解决方案:
- 改迭代写法(显式栈模拟)
- 编译时增加栈空间(GCC:
-Wl,--stack=268435456) - 尾递归优化(C++20
[[clang::musttail]])
5.2 浮点精度陷阱
典型案例:几何题判断三点共线
正确写法:
cpp复制bool isCollinear(Point a, Point b, Point c) {
// 使用交叉积避免除法
return abs((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x)) < 1e-9;
}
5.3 输入输出加速
C++终极优化(耗时减少85%):
cpp复制ios::sync_with_stdio(false);
cin.tie(nullptr);
cout << fixed << setprecision(8);
6. 训练成果与演进
经过87天持续训练(累计261题),关键指标变化:
| 指标 | 初期(1月) | 当前(3月) | 提升幅度 |
|---|---|---|---|
| AC首通过率 | 23% | 68% | +195% |
| 代码行数/题 | 45.2 | 28.7 | -36% |
| 平均耗时 | 38min | 19min | -50% |
| 一次编译通过率 | 51% | 89% | +74% |
下一步重点突破方向:
- 多线程并发题目(信号量/原子操作)
- 线段树优化DP(如区间最值维护)
- 提交代码自动生成测试数据(Python脚本)