ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

天梯赛L2备赛复盘:从翻车题到稳定输出的实战策略

天梯赛L2备赛复盘:从翻车题到稳定输出的实战策略 3月3号是周日我们队的固定训练日。我打开PTA平台翻到天梯赛题集的时候页面上的倒计时提醒我距离正式比赛已经只剩一个多月的窗口期。队里不少队友还在刷L1保底但我心里清楚天梯赛这种十人团队赛L1属于人人能拿、拿了也拉不开差距的基础分真正决定队伍排名的是L2那一组进阶级题目能稳定做出几道。所以我给自己定的主题很直接那一天先不管L1用整个下午集中刷L2把这个训练日当成正式比赛前的摸底考。这篇文章就是当天训练的完整记录包括我的选题思路、两道翻车题的详细复盘、训练中暴露出来的三个隐藏问题以及后续一个月我打算怎么调整节奏。如果你也在备赛天梯赛刷L2刷得有点茫然或者已经过了L1但觉得L2每一题都像新题那这篇应该有点参考价值。1. 3月3日的训练配置与选题思路1.1 为什么在3月这个节点死磕L2天梯赛的题目要分三档看待L1是入场券考的是程序能不能编译、循环写得顺不顺、简单字符串处理会不会漏边界这些题只要基础语法过关练熟之后基本是肌肉记忆不会给团队总分带来额外惊喜。L2才是真正的分水岭它不考特别深的算法但考得特别杂——链表的增删改查、二叉树的各种遍历、并查集合并、简单图论最短路、复杂模拟题的阅读能力全都会出现在L2里。L3则是另一个层级的竞赛题多数队伍能稳定AC一道就已经算是超额完成任务。对我们这种中游队伍来说比赛策略其实非常透明L1争取全拿L2尽量多拿L3靠运气。由于L1缺少区分度、L3性价比太低唯一值得下重注的就是L2。练L2等于同时训练读题速度、代码实现速度和常见数据结构的熟练度投入产出比最高。3月3日那一天我给自己定的及格线是五道L2这个数字不是拍脑袋定的——我们队的校内积分赛就是按这个标准排位的个人稳定做对五道左右贡献就能排到中上做三道以下基本属于拖后腿。1.2 当天的做题清单与最终战果把当天实际刷过的题和结果列成表格复盘的时候会看得非常清楚。这个表格是我当时记在笔记本上的原始版本包含题号、题型方向、当日结果和卡住的核心原因题号题型方向当日结果卡住的核心原因L2-001 紧急救援图论最短路路径还原未完成Dijkstra上叠加路径计数与最大点权和逻辑容易乱L2-002 链表去重链表模拟一次AC输出格式用%05d之前踩过坑所以比较顺L2-006 树的遍历递归建树层序输出第二遍AC递归区间切分时左右子树边界差一位L2-022 重排链表链表模拟一次AC链表长度奇偶判断容易漏写之前先画了图L2-029 小字辈树/记忆化搜索改了一版过直接递归会重复计算需要记忆化L2-034 口罩发放复杂模拟卡了一小时两个输出列表混在一起排序规则搞反这张表比当天AC了几道题更有价值。两个链表题都一次过了说明之前专门练链表模拟没有白费而树的遍历、小字辈、口罩发放这三道题都出现了反复说明我的主要短板不在“会不会写”而在边界处理、输出组织和复杂规则提取上。1.3 限时模拟的环境设置训练环境建议按比赛标准来搭不然练出来的感觉是失真的。我的做法是开一个两小时的倒计时整个过程中间不切网页、不刷论坛、不看题解编译器用自己最熟的C17不开网络搜模板旁边放一张草稿纸只记录三样东西——卡住的题号、卡住的原因、预估剩余时间。这样最后复盘的时候能直接看出每道题的时间黑洞到底在哪里。那天的限时跑下来我的时间分配大致是前40分钟做了L2-002和L2-022两道链表题中间50分钟全部耗在L2-034上剩下30分钟被迫在L2-006和L2-029之间抢救最后L2-029勉强改出来。这个结构非常不健康。一道复杂模拟题最多只该占20分钟一旦超过就应该先跳过做后面的题等第一轮扫完了再回来啃我那时候明显缺少这种“止损”意识。2. 翻车复盘一L2-034口罩发放排序线索是两条2.1 这道题表面考模拟实际考信息拆分L2-034是往年天梯赛的真题题面很长信息量很大。表面上看它考的是模拟实际上同时考了三个点一是能不能从长题面里提取出真正的规则二是能不能分清题目最后要求输出的两类名单三是会不会处理身份证号相关的排序和比较。很多人一看到长题面就开始慌其实拆开就一句话有一批人反复提交申请按某条规则判断谁有资格领取口罩最后按输入顺序输出有资格的人同时把你收到的所有发热人员单独记下来最后按身份证号字典序输出。难就难在“同时”。这两个输出有各自独立的顺序规则但来自同一批输入。我当时的第一版代码把符合领取条件的人和发热人员全部塞进了同一个结构里然后在输出阶段才想着用条件过滤。结果就是顺序乱成一团有资格名单要求“按提交顺序”发热名单要求“按身份证号排序”同一个容器里根本没法同时满足这两种规则每次排序都会把另一边打乱。2.2 一个vector装两条逻辑线的惨案我第一版逻辑看起来每一个判断都有每条记录输入之后先判断是否发热发热就打算塞进一个列表再判断此人是否有资格购买有资格也塞进同一个列表最后统一排序输出。听起来好像都考虑了问题出在哪里呢出在排序规则互相污染有资格购买的名单要求按提交顺序输出发热名单要求按身份证号排序。如果你把两组人放在同一个vector里不管你用什么排序键都会破坏另一组的顺序。而且还有一个更隐蔽的坑同一个人可能在多条记录里反复出现。发热名单要不要去重、有资格购买的人能不能重复领取都必须严格按题面来。我当时自作主张去重结果反而少输出了一条越改越懵最后发现自己根本是在跟一个错误的数据结构较劲。2.3 正确结构为每个输出单独开一条管道修通之后我发现正确做法其实特别简单关键是思路要先转过来为两种输出分别建立独立容器互不干扰。有资格购买的人用一个vector保存记录顺序就是输入顺序所以根本不需要排序发热人员另用一个容器保存最后单独按身份证号排序。如果确定身份证号不会重复直接用map以身份证号为key存输出时遍历map就是天然字典序如果可能重复就输出前打标记去重。关键代码骨架大概是这个样子vectorNode okList; // 有资格购买的人保持输入顺序 setstring hasGet; // 标记已经领取过的人 mapstring, Node feverMap; // 发热人员按身份证号排序 // 按输入顺序逐条处理 // 1. 如果发热写入 feverMap // 2. 如果提交时间在有效窗口内 且 未领取过则 push 进 okList同时在 hasGet 标记这里的教训不是“题难”而是我一开始没把输出当成独立的管道。比赛里这种结构非常常见同一个输入按不同规则生成多个输出每个输出有自己的顺序。只要脑子里先想清楚“最终要产出几份名单、每份名单用什么顺序”代码结构自然就清楚了。2.4 辨识“双输出”题的通用信号复盘时我总结出一个很实用的识别方法看题目的末尾部分如果它用“同时”“另外”“分别”这类词给出了两个或以上的输出要求那在设计数据结构时就必须从一开始为每个输出单独准备容器。顺序型输出就用vector保持原序字典序输出就用map或者最后统一排序。一边读数据一边塞进对应容器最后各走各的输出逻辑基本不会乱。这个经验不只适用于口罩发放这一道题。天梯赛很多L2模拟题都爱在最后一两句安排多个输出要求本质考的就是代码组织能力。我后来再遇到这种题第一件事不是急着写输入输出框架而是先数清楚题目要求输出几份东西。3. 翻车复盘二L2-006树的遍历递归边界差一步错一路3.1 中序后序建树的本质根在后序末尾位置由中序决定当天最后三十分钟我碰到L2-006。这道题给出一棵二叉树的中序序列和后序序列要求输出层序遍历结果。核心思路其实一句话就能讲完后序序列的最后一个节点一定是整棵树的根拿着这个根去中序序列里找到它的位置左边就是左子树的中序区间右边就是右子树的中序区间然后递归往下建树。我第一版代码的问题出在区间切分上具体是后序序列的右子树起点算错了。很多人第一次写都会踩这个坑左子树区间和后序区间的关系总是差一个下标。正确的写法是每个递归函数同时接收当前子树的中序区间和后序区间先用后序的最后一个元素确定根再去中序里数出左子树的长度最后用这个长度去切后序区间而不是凭感觉平移。我当时最后使用的核心函数长这样int build(int inL, int inR, int poL, int poR) { if (inL inR) return -1; int root post[poR]; // 后序最后一个节点是根 int pos -1; for (int i inL; i inR; i) { if (in[i] root) { pos i; break; } } int leftLen pos - inL; // 左子树节点个数 lc[root] build(inL, pos - 1, poL, poL leftLen - 1); rc[root] build(pos 1, inR, poL leftLen, poR - 1); return root; }注意后序右子树的起点写成poL leftLen不要写成poL leftLen 1。根虽然在 poR 位置但右子树区间并不需要为根预留额外偏移这是这个模板里最容易错位的地方。3.2 三个边界细节每一个都让我白交一发第一空区间判断用中序的inL inR不要用后序去判断。因为后序区间在递归中可能因为切分方式产生一些看起来合法的区间但中序区间才是真正决定子树范围的依据。第二找根在中序里的位置时每一次都要在当前子树的中序区间内找不是在整个原数组里找。我第一次写的时候用全局数组下标直接定位第二次递归进入子树时位置严重错位建出来的树完全是歪的。第三节点编号在题里通常就是1到N所以用数组存左右孩子最方便不用写指针版二叉树层序输出时从根开始用队列BFS即可。层序输出本身只占这道题最后10%的工作量根节点入队弹出时依次把左右孩子入队直到队列为空。真正要注意的只有分隔符——天梯赛这类题特别喜欢让你最后一个数字后面不留空格。统一做法是“第一个节点输出前不打空格后面每个节点输出前加一个空格”这比输出完再想办法删末尾空格要稳得多。3.3 数据结构题练到“肌肉记忆”才算会当时同队的朋友看了一眼我的代码很疑惑地说这题你之前不是见过吗确实“中序加后序建树”这个套路我记得但真正动手时每个递归边界上都要犹豫几秒犹豫多了就在这种题上耗掉了超过二十分钟。考场上没有那么多时间给你回忆模板。后来我给自己定了一条规矩任何一道L2数据结构题如果不能在草稿纸上用三分钟写出核心框架说明熟练度不够回头必须复现到能背下来的程度。中序加后序建树本质上和链表反转、并查集合并一样属于必须形成肌肉记忆的代码骨架。天梯赛L2的树题考的就是你有没有把这套东西练到不用动脑。4. 一次训练暴露的三个隐性短板4.1 读题慢样例能过不等于题目读对那天我粗略估算平均每道题读题用了5到8分钟。L2题面普遍偏长尤其是模拟题样例只是最浅层的信息。我读题有个不好的习惯先看样例再用样例反推规则推不动才回头读题面。这个习惯对短题面有效对L2这种长题面很危险因为样例往往只覆盖最顺利的情况隐藏规则全在题面的角落里。反击发放题里我在样例上表现良好但自己构造的测试数据一深就发现“已经领取过的人不能重复领取”这个隐藏条件没处理。正确的读题姿势应该是先完整读一遍题把规则逐条列成清单再对着样例把清单里每一条验证一遍。把读题从“看故事”变成“提取规则”之后模拟题的准确率明显上升。4.2 输出陷阱格式错误比逻辑错误更冤天梯赛判题和传统OJ一样严格多一个空格、少一个换行都算格式错误。常见陷阱包括行尾不能有空格但行内必须有分隔符多个整数用单个空格分开输出字符串时大小写敏感日期、编号、身份证号这类长数字必须用字符串类型读入否则前导零会丢。这些坑单独拎出来都不难但组合在一起会大量消耗罚时。我的应对办法是把常用输出模式写成小工具函数比如“输出一个列表、题目要求末尾无空格”这种重复操作写好模板之后所有题直接复用。长数字ID统一用string读入必要的时候再转long long。这种做法看起来浪费实际上能避开天梯赛大量藏在输出细节里的罚时。4.3 容器选择的心智模型当天另一道题L2-029小字辈第一版递归超时改成记忆化才过。这暴露出我对“树的高度、代数”这类问题缺少快速反应只要题目涉及从叶子往根找、找祖先、找层级就应该想到记忆化或者路径压缩而不是每次都重新递归跑一整条链。复盘的时候我把容器选择的心智模型也梳理了一遍需要查重时先想set需要按key配对、并且天然按key排序输出时想map只需要保持输入顺序、最后线性遍历时想vector需要“来过一次就不再处理”时想bool数组或set。L2的题基本离不开这几个容器。链表题更是这样用结构体数组加地址串接模拟比真的写指针链表快得多也稳得多。我第一次写链表去重时用的是真指针删除逻辑绕来绕去容易出错后来改成结构体数组一次就过了。天梯赛时间紧数据结构的选型标准应该是简单可靠而不是性能最优。5. 下阶段练法调整把L2刷成稳定输出5.1 优先级排序先练树、链表、并查集3月3日训练结束后我把正式比赛前最后一段时间的训练重点定了下来优先级是这样排的链表模拟高。几乎每年都有练熟就是送分重点练结构体数组、地址串接、奇偶长度判断。树的遍历与重构高。中序加后序、前序加中序、层序变体都是固定套路必须形成肌肉记忆。并查集高。模板只有十几行考的是合并逻辑和统计集合数量的附加操作。栈和队列应用中高。主要和二叉树层序、表达式处理、括号匹配绑定出现。图论基础中。最短路和DFS、BFS会涉及但L2的图论题大多不难重点是把模板打熟。复杂模拟中。不考算法考读题和代码组织每天练一道保持手感。按这个优先级我给自己定的每日方案是每天两道L2一道数据结构题加一道模拟题周末做完整的限时赛每次练习后必须复盘写清错误类型是读错题、边界漏、语法错还是数据结构选错连续记录一周就能看到自己的错误分布。5.2 卡题超过20分钟就切题那天最大的时间浪费就是L2-034卡了四十分钟还不肯放手。之后训练我给自己立了规矩限时模拟中途一道题卡超过20分钟先标记为“第一轮未完成”立刻切下一题。等把能拿的题都拿完之后再回来处理而且回来之后先重读题面而不是对着写了一半的代码继续改。这个规矩不只是时间管理也是心态管理。连续卡题会带来很强的挫败感后面的题本来能做也容易因为心态崩而丢分。及时切换题目既保住基础分又给大脑一个缓冲。回头看那道题时经常因为重新读了题面发现自己先前的理解本身就有偏差。5.3 复盘是训练的一半很多队友练题的方式是AC一道、开心一下马上刷下一道。我练题的方式刚好相反一道题AC之后会强迫自己调出错误提交记录对比正确版本找出导致错误的那个具体点然后写一行注释记录原因。错误代码是比AC代码更值钱的东西因为AC代码只有一种坑却有无数种。这一个月练下来我的直观感受是L2刷题数量远没有“每道题是否总结”重要。盲目刷一百道题不总结错误类型会反复出现认真复盘二十道题常见坑基本能全部踩完一遍。天梯赛的L2本质上考的是熟练度和细致度这两样东西只能靠有针对性的刻意练习积累而刻意练习的核心就是每次训练后都回答一个问题这一题我凭什么能过下一题我凭什么保证还过。当时我在笔记本最后一页写着如果每个周末都能像3月3日这样把翻车的题吃透到能给别人讲清楚的程度比赛时至少能多拿一两道L2的分。
返回列表