免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

寒假上机打卡复盘:算法刷题与数据库实验的完整实践

寒假上机打卡复盘:算法刷题与数据库实验的完整实践 其实最开始想把这天上机打卡的完整记录发出来是觉得“打卡”这两个字太常被贴在各种自律社区里了以至于大家默认打卡就是拍张照片、发条动态、打完就走。但我自己寒假在家连续做了二十多天上机训练之后越来越觉得打卡的本质不是“证明我来过”而是“记录我今天解决了什么”。1月28日这一天正好是我整个计划里节奏最稳、收获也最典型的一天就把这天的完整过程、思路和踩坑全部复盘出来分享给同样在刷题、刷课、刷实验报告的朋友。这篇文章的核心内容就三块一是这天上机打卡的目标设计和内容安排二是每个环节的实际执行过程和细节三是当天遇到过的问题和我的排查思路。适合刚启动寒假自律计划、或者正在备考考研复试/春招笔试需要系统化上机训练的人参考。1. 整体设计与思路拆解1.1 为什么非要“上机打卡”而不是随便学几小时我先说一个很现实的观察寒假在家大多数人每天也会摸电脑但时间往往被切割成短视频、游戏、聊天这些碎片真正集中在代码编辑器或者实验平台上的连贯时间非常少。如果只靠“我今天学了一会儿”这种模糊感觉到晚上复盘时往往什么都说不出来。“上机打卡”这个词我给它下的定义是在固定时间段内把全部注意力投放到需要实际操作才能完成的任务上并以可验证的结果作为这次打卡完成的依据。它强调的是“可验证”。比如1月28日这天我的目标是完成三道算法题、一次数据库实验复现、以及整理一份错题笔记。每一项都有一个明确的产出物而不是“我看了两个小时视频”。这样做的好处很明显任务一旦可以被验证拖延和走神的空间就会被压缩。你很难在“必须提交一道通过全部测试用例的代码”这件事上假装努力。打卡的意义不是给朋友圈看的而是给自己建立一个反馈机制。1.2 这一天卡在什么时间节点目标如何拆解选择1月28日本身没有什么特殊含义但它处在一个特定的阶段寒假已经过半春节还没到大多数人手头既没有“刚放假必须放松”的借口也没有“马上过年了先歇两天”的心理压力。这是整个假期里最适合做高强度专注训练的窗口期。我在设计这一天目标时没有贪多。很多人的打卡失败就是败在目标太多总想一天之内把算法、八股、项目、英语全塞进去。我用的是“121”结构模块具体内容时间预算产出物1道每日一题LeetCode 216组合总和 III1小时通过全部用例的提交记录2道专项复习链表反转类 二叉树层序遍历1.5小时两页手写思路 可运行代码1项实验复现数据库事务隔离级别实验1.5小时完整的实验截图与结论记录这个组合覆盖了“新题保持手感、旧题巩固套路、实验弥补工程盲区”三个维度。比单纯刷题多了一层实验内容让整个上午和下午的节奏不至于单调。1.3 给“打卡”加一个明确退出的标准执行计划的时候我给自己定了一个原则每项任务必须做到“可以交代”的程度才算结束。所谓“可以交代”就是如果现在有人问我这项任务做了什么我能直接给出答案、拿出结果。这个原则帮我避开了两个坑第一个坑是在一道题上死磕一整晚。如果一道题到了预定时间还是没思路正确的选择是标记为困难、去查题解、理解后重新手写一遍而不是无限期耗下去。第二个坑是做实验时反复“试按钮”不记录过程。数据库实验如果只是点鼠标成功一次隔天再打开大概率还是不会必须把每一步的操作意图写明白。比如数据库事务隔离级别这个实验我的检查标准是能否不看笔记直接用一组并发操作展示出“读已提交”和“可重复读”的差异。如果不能就说明还没真正掌握。2. 核心细节解析与实操要点2.1 环境准备别小看开工前十分钟上机打卡最怕的不是任务难而是人到电脑前了环境还没准备好。1月28日这天我在正式开工前做了一次环境检查大概花了十分钟内容包括确认本地开发环境的编译器版本和依赖库没有因为系统更新而变动。检查算法刷题平台的登录状态和上次提交记录确保没有未提交的半成品代码。为数据库实验启动 Docker 容器确认 MySQL 服务运行正常。我用的镜像是 mysql:8.0端口映射 3306数据目录挂载到宿主机方便实验后统一清理。清空桌面上无关的聊天窗口和浏览器标签页只保留编辑器、终端、笔记软件三个窗口。这些听起来很琐碎但实测下来非常值。去年冬天有一次我打开数据库连接工具却发现服务没启动排查环境花了将近半小时当天状态被彻底打乱。现在我会把环境检查当作打卡的第一步优先级等同于热身。2.2 每日一题的具体解法与手写推演1月28日的每日一题是组合总和 III题目要求找出所有相加之和为 n 的 k 个数的组合且组合中只允许使用数字 1 到 9每个数字最多使用一次。这是一道非常标准的回溯算法题难度不大但如果想写得干净利落还是有几个细节要考虑。我采用的思路是标准回溯加剪枝。核心代码结构如下def combinationSum3(k: int, n: int) - List[List[int]]: res [] path [] def dfs(start: int, target: int): if len(path) k and target 0: res.append(path[:]) return if len(path) k or target 0: return for i in range(start, 10): if i target: break path.append(i) dfs(i 1, target - i) path.pop() dfs(1, n) return res这段代码里最关键的是if i target: break这一行剪枝。因为数字是从小到大枚举的如果当前数字已经大于剩余需要的目标值后面的数字只会更大所以可以直接终止循环。这个剪枝能让递归树的规模缩小不少。写完通过用例后我没有急着做下一题而是花了大概十五分钟在纸上把递归树画了一遍把一次完整的回溯过程包括进入递归、保存结果、回溯撤销这三个步骤手动演练了一次。这种手写推演对加深理解特别有帮助尤其是回溯算法里“撤销选择”这一步很多初学者总是忘记导致结果集合里出现重复或残留数据。2.3 专项复习链表反转与二叉树层序遍历的套路总结专项复习的两道题我选了代表性的“反转链表 II”和“二叉树的层序遍历”。选它们的原因很简单反转链表系列几乎是大厂面试的高频考点而层序遍历则是二叉树题目里最常见的基础框架。反转链表 II 要求反转从位置 left 到 right 的链表节点。我第一次写这道题的时候被边界条件折磨了很久。后来我总结出一套稳定的四步走添加一个虚拟头节点dummy避免处理 left1 时的特殊逻辑。找到 left 节点的前驱节点pre。从 left 开始依次把后面的节点搬到pre后面重复 right-left 次。返回dummy.next。关键在于第三步的“头插法”思想每次把当前节点的后继搬到前驱节点后面而不是真的去反转子链表。代码写起来会清爽很多。二叉树层序遍历这道题则是一个标准的 BFS 模板应用。用队列维护当前层的节点每一轮循环先记录这一层的节点数量再依次出队处理并加入下一层节点。我在复习这两道题时刻意没有看旧代码而是直接打开编辑器重新写。写完以后再和之前的版本对比看差异在哪里。这个方法很推荐因为人很容易对看过的代码产生“我会了”的错觉真正合上答案动手写一遍才知道漏洞在哪。2.4 数据库实验事务隔离级别的复现思路下午的数据库实验我选的是“事务隔离级别”这个主题。它在面试里也经常出现但很多人的理解停留在概念层面真正让两个事务并发跑起来观察不同隔离级别下的差异又是另一回事。实验环境是 MySQL 8.0通过 Docker 运行。我用两个终端会话模拟两个并发事务着重验证 READ COMMITTED 和 REPEATABLE READ 两种隔离级别下的行为差异。实验步骤大致如下创建一张简单的账户表包含 id、balance 两个字段插入一条初始数据。将当前会话的隔离级别设置为 READ COMMITTED。在事务 A 中开启事务并查询 balance。在事务 B 中修改 balance 但不提交。回到事务 A 再次查询能读到 B 未提交的数据吗这个现象在课程里叫“不可重复读”还是“脏读”然后再把隔离级别切换到 REPEATABLE READ重复上述步骤观察行为差异。我发现很多初学者会搞混“脏读”和“不可重复读”但其实在实验里看一次就很难忘记脏读是指事务 A 读到了事务 B 修改过但还没提交的数据如果 B 回滚A 就读到了一个不存在的数据。不可重复读则是在同一个事务里两次相同的查询因为其他事务提交而返回了不同的结果。MySQL 默认的 REPEATABLE READ 级别下由于多版本并发控制机制的存在事务 A 在开启事务后创建了读视图之后即使 B 提交了新数据A 再次查询读到的仍是视图建立时的快照所以结果保持一致。我的实验记录里专门有一栏是“现象解释”把每一行结果的缘由都写清楚。这比单纯截图保存要有效得多。3. 实操过程与核心环节实现3.1 完整的时间轴与节奏控制1月28日当天我的时间安排和实际执行情况如下时间段计划内容实际完成情况08:40-09:00环境检查与任务清单刷新完成并顺手处理了 Docker 镜像更新09:00-10:00每日一题组合总和 III30分钟写完通过20分钟画递归树10分钟记录10:10-11:40链表反转专项复习完成反转链表 II两版代码对比发现一处冗余判断14:00-15:30二叉树层序遍历专项复习完成模板重写并延展了之字形遍历变体15:40-17:10数据库事务隔离级别实验完成 READ COMMITTED 与 REPEATABLE READ 对比实验17:20-18:00错题与笔记整理整理 3 道题 1 份实验报告同步到本地知识库这张时间表看着很常规但真正执行时最影响节奏的是午休后的状态恢复。我刻意把纯算法任务放在上午把实验类任务放在下午因为实验操作性强即使略困也能靠动手维持专注度。3.2 每日一题的完整推导与提交记录以每日一题为例我把整个推导过程完整写在这里方便你对照。题目要求从数字 1 到 9 中选取 k 个不重复数字使它们的和为 n。最先反应到脑子里的方案其实是暴力枚举因为 1 到 9 一共才 9 个数字全部组合 C(9,k) 也不会太大。但算法题不能只满足于“能跑”还要满足“思路可迁移”。回溯算法的意义在于它不仅能解决组合求和问题还能扩展到排列、子集、分割等更复杂的场景。实际编码过程中我第一个版本漏掉了target 0的剪枝条件导致很多无效递归继续走下去。后来补上之后提交一次通过。通过并不代表完全理解所以我继续做了两件小事第一把递归过程输出到终端观察每一步的 path 和 target 变化。这一步能直观看到回溯发生的时机。第二尝试把递归改成迭代写法虽然代码变长了但能帮助理解系统栈在递归中的真实作用。这两件小事花了额外二十分钟但收益很大。那天晚上我复盘时发现自己对“回溯”的理解比前一天清晰了一个台阶。3.3 数据库实验的真实操作指令与结果记录数据库实验这块我把关键操作指令整理成一个可直接复用的清单。我用的是 MySQL 命令行客户端通过 Docker 进入容器操作docker exec -it mysql8 mysql -uroot -p进入后先创建实验库和表CREATE DATABASE IF NOT EXISTS isolation_demo; USE isolation_demo; CREATE TABLE account ( id INT PRIMARY KEY, balance INT NOT NULL ); INSERT INTO account VALUES (1, 100);验证 READ COMMITTED 下的不可重复读行为时我做了这样的操作序列终端 ASET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; SELECT * FROM account WHERE id 1;此时终端 B 修改数据但不提交SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; UPDATE account SET balance 200 WHERE id 1;然后回到终端 A再次执行相同的查询发现结果是 200。这个现象意味着终端 A 的两次读结果不一致也就是“不可重复读”。这是因为 READ COMMITTED 级别下每次 SELECT 语句都会生成新的读视图因此能读到其他事务已提交的数据。接着切到 REPEATABLE READ 重复同样操作终端 A 第一次查询后终端 B 修改并提交终端 A 再次查询发现仍然是 100。这个差异就是多版本并发控制创建的快照在起作用。我把每一步的现象和原因对照着写进了实验报告并特别用醒目的方式标注“读已提交解决的是脏读问题可重复读解决的是不可重复读问题而不是解决幻读”。幻读在 MySQL 的默认隔离级别下也有独立处理机制但是概念辨析特别容易混需要额外注意。3.4 笔记整理方法用手工记录倒逼思维整理当天最后一个环节是笔记整理。我不太喜欢用自动回放工具而是坚持手动整理因为手动输出的过程本身就是一次知识的重新编码。我的笔记模板分四个部分问题描述用一句自己的话复述题目要求禁止直接复制题干。核心思路画出数据结构变化示意图用箭头表示指针或节点移动方向。关键代码片段只记录最核心的几行不贴全量代码。复盘备注写出“这题我还有哪里不懂”或者“这个套路还能用于什么场景”。以反转链表 II 为例我画了一张“pre 节点不断头插”的示意图箭头方向是这个题最容易出错的地方画完再看代码整个人都通透了很多。4. 常见问题与排查技巧实录4.1 打卡中断连续性比单次强度更重要我见过太多人打卡失败不是因为某一天任务太重而是因为在一次任务太重导致加班熬夜之后第二天就彻底放弃了。所以 1 月 28 日这天我特别控制强度刻意控制在 6 小时以内留出晚上运动的时间。如果哪天真的有事我会把打卡目标临时压缩到“只做一道简单题 阅读一篇技术文档”允许自己提前结束但绝对不允许零记录。这个策略我的执行效果很好。连续打卡的重心不在“每天都很猛”而在“每天都在动”。4.2 代码卡住超过 30 分钟怎么办我在当天做二叉树层序遍历的变体时也遇到过卡住的情况。这里说的卡住不是完全没有思路而是想到了用队列但在处理“如何区分当前层和下一层”时写出来的代码总是少处理一个节点。我的排查习惯分为三步先不查题解自己在纸上按例子手推一遍看是逻辑错误还是实现错误。如果纸上推演没问题就加打印信息输出每一轮循环后队列的内容对比预期。如果还是找不到就果断去查题解但查完以后一定要合上答案自己重新写一遍。每次用这套流程最后都能定位到问题。很多“卡住”其实不是不懂原理而是在某个边界条件上忘了处理。比如层序遍历这题如果不在每轮循环开始时记录size len(queue)而是直接while queue就会把不同层的节点混在一起。4.3 环境配置问题Docker 容器突然连不上这一天下午刚开始做数据库实验时我就差点被环境问题劝退。用 Navicat 连接 MySQL 时报错提示连接被拒绝。排查思路如下先检查容器是否在运行docker ps -a。发现容器状态是 Exited。查看容器日志docker logs mysql8。发现因服务器重启后没有执行容器自启动策略容器直接挂了。用docker start mysql8启动容器再次连接恢复正常。这类问题很常见不用慌。但建议给数据库容器加上--restartalways参数防止类似情况再次发生。另外我还遇到过一次因为权限问题导致无法远程连接的情况。解决方案是在容器内创建一个专门用于远程连接的用户并授权CREATE USER remote_user% IDENTIFIED BY your_password; GRANT ALL PRIVILEGES ON *.* TO remote_user%; FLUSH PRIVILEGES;注意生产环境绝对不能把权限开得这么宽本地实验环境为了方便倒是无所谓。4.4 笔记无法坚持降低单篇笔记的成本很多人的知识库建设计划都会在寒假中途报废最大的原因是笔记成本太高。我自己早期写一篇笔记可能要四十分钟后来我把“发布级笔记”和“随手记”分开打卡当天只需要完成“随手记”级别的记录周末再统一整理发布级内容。随手记的标准是自己能看懂就行包括照片、截图、涂鸦、代码片段、语音备忘都可以。这样能大幅降低打卡的心理门槛。1 月 28 日当天我很多原始记录都是用零散句子写下来的真正整理成结构化笔记是在当天晚上动作也快了不少。5. 复盘价值与可复用方法5.1 如何判断一次打卡是否真的有价值打卡是否有效我的判断标准是看当天结束后有没有留下三种东西新的知识增量、修正的旧认知、和可供复用的模板。1 月 28 日这天我的知识增量主要是弄清楚了 READ COMMITTED 与 REPEATABLE READ 在实际并发场景下的表现差异修正的旧认知是发现自己在“回溯算法剪枝条件”上经常漏写target 0复用模板则是把 MySQL 双终端测试事务隔离级别的方法沉淀下来以后遇到类似问题可以直接套用。如果一天结束这三类东西一样都没有那我觉得不管打卡打了多少个小时本质上还是无效努力。这个判断标准可以直接移植到任何技能训练里。5.2 把“打卡”变成可持续的小系统最后我想聊点超出这一天的内容。把“1 月 28 日上机打卡”单独拿出来看它只是一天的记录但真正有价值的是让“打卡”成为一个可持续的小系统。我的做法是准备一个简单的月度打卡表表头字段包括日期、核心任务、完成情况、耗时、问题记录、明日改进。每天晚上填一行周五复盘一次。这个习惯坚持一个月之后回看表格找到的问题数量会比凭印象总结多出不少。如果已经有三个月以上的打卡数据还可以按周统计任务类型和时间分布确认优先级有没有走偏。比如我前两周发现自己算法题占比高得离谱实验和理论学习被严重挤压后面就有意识地调整了比例。5.3 给不同阶段读者的具体建议如果是刚开始做上机打卡的读者我强烈建议第一周只安排平时训练量的一半目标是找到自己能在固定时间段内集中多长时间的体感。不要一上来就按“考研冲刺计划”的强度要求自己那样大概率坚持不过三天。对于已经有一定基础、正在秋招或复试准备中的人打卡内容建议以“为主战场查漏补缺”为原则比如你算法题已经刷了一百多道那上机打卡的重心就应该转移到真题模拟和系统设计题临场书写上。还有一个适用于所有人的建议每天打卡时选一道“稍微超出当前舒适区又不会完全摸不到思路”的题目。这类题处在学习的最近发展区带来的提升最明显。如果选的题都太容易打卡会变成舒适区的重复劳动都太难又会打击积极性。我在 1 月 28 日当天选的组合总和 III 就是这样的题目类型算是对回溯算法老知识的一次进阶巩固也是这个道理。
返回列表