
牛客网刷题这件事我前后断断续续做了两年从当初连题解都看不懂的小白到现在能稳定在笔试里AC七八成题目中间踩过的坑比做过的题还多。这篇继续说牛客网刷题的正经路子。上一期讲的是怎么注册、怎么进题库、初级题怎么入手这期直接上硬货ACM模式的输入输出怎么处理、专题怎么刷、C和C在OJ上有哪些要命的细节、以及在牛客刷题和别家平台到底有什么本质区别。不管你是为秋招笔试准备还是被CSP-J这类竞赛拉去陪跑又或者单纯想练练C语言、数据结构的底子这篇都能给你一点能直接用上的东西。1. 牛客刷题的正确打开方式先搞懂平台的隐藏规则1.1 ACM模式是一场隐形的成人大考很多第一次用牛客刷题的人最容易栽跟头的地方反而不是题目本身而是它的输入输出模式。力扣默认给你一个函数你只需要把函数体补全数据从参数里递进来结果return出去就行牛客的OJ不是这样牛客套的是ACM比赛那套标准你得自己写while(scanf()!EOF)自己处理一行数据里多个数字的分隔自己判断什么时候输入结束。我当年第一次在牛客写题用C语言做“输入两个数输出它们的和”想着这不就是ab吗结果我直接写了scanf(%d %d, a, b); printf(%d, ab);就提交了换来一个“段错误”。后来才明白真实笔试里输入是一堆测试用例可能中间还有多组数据你只读一次怎么行正确写法是#include stdio.h int main() { int a, b; while (scanf(%d %d, a, b) ! EOF) { printf(%d\n, a b); } return 0; }这看起来简单但它代表的是两种完全不同的解题思维。力扣帮你把“怎么把数据取出来”这件事做完了你只负责算法牛客要求你连数据怎么读取、怎么分组、怎么结束都要自己handle这就对工程性提出了要求。你写的不是一个“函数”是一个“完整程序”。在牛客刷题之前先把牛客OJ的“输入输出处理”专题刷一遍大概是十几道题覆盖了多行输入、不定行输入、字符串包含空格、逗号分隔输入这些常见场景。真的千万别跳过这一步这就是牛客上的隐形考试。很多C语言刷题刷到崩溃的同学问题不在算法上而是连“怎么把题目给出的数据读进来”都没搞定。1.2 牛客、力扣、洛谷各司其职别用错了地方刷题平台的选择其实反应了你的目标。我在牛客、力扣、洛谷上都有账号切着用了这么久得出一个很实用的结论三者的定位是不同的。力扣适合用来练算法思路它的“核心代码模式”屏蔽了输入输出的干扰你可以专心研究动态规划的状态转移、图论的最短路、线段树的区间合并这是它的优势。而且力扣的题解社区质量极高评论区里常有降复杂度的神仙思路。洛谷更适合竞赛生。它的题目面向NOIP/CSP体系难度梯度拉得非常开从红题入门到黑题地狱都有题目描述中规中矩考察的更多是纯粹的算法与数据结构能力。如果你想打CSP-J洛谷的“题单”功能很值得用。牛客最大的价值在于“贴近国内笔试”。国内互联网公司笔试很多直接就是牛客这套系统或者长得很像的系统你提前在牛客上把输入输出练熟了笔试的时候就不会因为交互方式陌生而浪费大把时间。另外牛客的题库里很多题直接标着“XX公司202X秋招笔试题”这个信息量比任何模拟题都大你可以按公司筛选真题针对性练习这比漫无目的地刷题有效得多。所以我建议的安排是平时用力扣练算法思维用洛谷拉难度笔试前一到两个月切到牛客刷真题重点是适应它的ACM模式。如果你现在时间紧张只想用一个平台那就直接牛客。2. 按专题刷题别做无头苍蝇2.1 动态规划与贪心刷到“有感觉”才算数很多人刷题有个坏毛病今天做一道字符串明天做一道二叉树后天做一道数学题看起来很努力但实际效果奇差。牛客上的“专题训练”栏目是我见过最适合用来“按知识点击破”的地方。以动态规划为例这是笔试的大户也是很多人最头疼的板块。我的建议是从最基础的“斐波那契数列”、“爬楼梯”这种题开始理解什么是“重叠子问题”、“最优子结构”。然后做“01背包”、“完全背包”、“最长递增子序列”、“最长公共子序列”这四道经典题。这四道题吃透了牛客上八成以上的动态规划题你至少能写出暴力版本。我见过不少人的问题是一道题看题解看懂了第二天再写又不会了。这在我看来是正常的因为你只是在“看懂”层面还没有形成“肌肉记忆”。动态规划的题目套路其实非常固定先定义dp[i]的含义再找状态转移方程最后确定初始化和遍历顺序。这三步熟练之后你要做的就是练“识别”看到一道题想想它属于“背包类”、“区间类”还是“序列类”对应套模板。贪心的题目则要灵活得多。它的难点在于“证明这一题可以用贪心”以及“找到贪心的策略”。我推荐练牛客上的“合并区间”、“跳跃游戏”、“分发饼干”这几道经典题。“跳跃游戏”我做了三遍每做一遍都有新的体会最后才明白所谓贪心就是每一步都做出当前看起来最优的选择然后祈祷全局最优——当然心里要有数不是所有题目都能这样搞如果能后悔就考虑动态规划。2.2 链表、栈与队列笔试高频区要反复练习链表的题在牛客笔试里出现频率极高。为什么因为链表涉及指针操作既能考你对基本数据结构的理解又能考你的代码实现能力还容易挖出“边界条件没处理好”这种问题。牛客上链表的经典题“反转链表”一定是排在榜首的。这道题看起来简单但初学者写起来很容易绕晕。我提供一个我常用的写法用三指针法。pre指向已反转部分的头cur指向当前待反转节点next保存cur的下一个节点。每次循环做三步操作——先保存next再把cur指向pre然后pre和cur整体后移。字数不多但完全靠理解。如果你写链表题总容易出错排错时先在草稿纸上画图把每一个next指针的变化画出来。很多人在牛客写链表题报错之后看半天代码看不出问题就是因为脑子里没有那根“指针连接线”。栈和队列这边“用两个栈实现队列”这类题是必刷的因为它不是单纯考数据结构还考你“在受限条件下实现功能”的应变能力。反正像这类题在牛客上做至少一遍再用C手写一遍不要用库里的stack对基础知识的巩固非常有帮助。2.3 数学与数论从欧几里德算法说开去牛客上有一大类题目属于“数学题”这类题目不会直接告诉你“这题考数学”而是包装成一个实际问题但解法核心往往是一个数学结论。这类题目的代表就是各种与最大公约数、最小公倍数相关的题目而它们的基础就是欧几里德算法——也就是辗转相除法。欧几里德算法的实现代码极短小学课本里甚至也讲但它是很多数论题的地基。int gcd(int a, int b) { return b 0 ? a : gcd(b, a % b); }光是这个算法本身就可以变形出很多种考察方式求两个数的最小公倍数a / gcd(a,b) * b注意先除再乘防溢出、求多个数的公共gcd、判断两个数是否互质、甚至扩展欧几里德算法用来解形如ax by gcd(a,b)的方程。我建议把牛客上搜索关键词“gcd”或“公约数”把前两页的题过一遍。这些题多数是简单到中等难度用来练手很合适。做这些题你还能接触到“质因数分解”“快速幂”这些和数论相关的基础工具。数学类的题目核心思路是“缩小数据的规模”一个大数不好处理就想办法用模运算把它压小这一步决定了程序的性能。3. C与C刷题的硬核细节3.1 C语言的老毛病数组越界、空格符、EOFC语言在OJ上最大的优势是速度快但劣势也一样明显一切都要你手动管理出错的概率极大。我总结几个牛客刷题时C语言最常出的问题基本每个都是血泪教训。第一个是数组越界。牛客很多题的数据范围写得很明确比如“n不超过1000”那么int a[1000];就够了吗去看了看数据范围你就会发现有的题目说n1000实际上是n1000如果你只开1000最后一个位置就溢出了。我的习惯是数组一律多开5到10个位置int a[1005];宁可浪费也不要越界。第二个是scanf与getchar的混用。如果你前面用scanf(%d, n)读入一个整数后面又想用getchar()读入字符中间通常需要用getchar()把缓冲区的换行符吃掉否则你读到的可能是残留的\n。这个问题在牛客的字符串题目里尤其常见字符串题也是最容易让C语言初学者摔跟头的。第三个是EOF的判断。C语言必须在读取时判断返回值否则程序跑不到结束。但目前用C刷题的人越来越多C语言在牛客上更多的是一些老学长或者课程作业要求如果你不是对C有执念我建议用C把数据结构相关的题写了C语言主要用来理解底层逻辑效果更好。3.2 C的STL别当摆设五个高频容器要用熟C刷题比C语言舒服很多核心在于STL标准模板库。很多人学了C却只拿它当“带类的C”这是最浪费的用法。在牛客刷题你得把下面这些容器用熟。vector是动态数组刷题最常用没有之一。它替代了C语言中需要对数组动态分配内存的操作。推荐熟悉push_backsize以及通过下标或者迭代器遍历的方式。string处理字符串比C语言的字符数组方便太多了。遇到字符串题目可以直接用拼接用find查子串用substr取子串用sort排序等等效率和写在纸上的实现逻辑一样但写好检查的时间省下一大半。stack、queue、priority_queue是三类容器适配器分别应对栈、队列、优先队列的场景。括号匹配、单调栈、拓扑排序这些“名字一听就害怕”的题其实无非就是把数据往这些容器里放一放再取出来。map/unordered_map是哈希表后者效率更高用来做“值到信息的映射”特别好用。比如统计字符串中每个字符出现的次数mapchar, int mp;然后mp[c];几行代码搞定。如果是C语言你要么暴力开数组遇到char还能用ASCII码遇到字符串就抓狂要么自己实现一个哈希表复杂度完全不是一个量级。别嫌STL“太高级”而不去用。刷题拼的是“在限时内解决问题”STL就是帮你节省时间的最佳工具。当然面试问底层实现的时候你要能说出红黑树、哈希冲突这些但在刷题阶段先用起来用熟练再倒回去看原理顺序是这样。3.3 时间与内存怎么估算你的代码能不能过在牛客上刷题提交之后会遇到一个非常扎心的结果超时TLE或者超内存MLE。看不懂这两个词的先记下缩写以后会经常见到。很多初学者解决这类问题的思路是“换行输入”“加关闭同步的代码”——这些有作用但治标不治本。真正的做法是估算算法的时间复杂度看看你的代码在极端情况下会不会炸。一个粗略但有价值的参考标准一台现代评测机大约一秒能执行1e8次简单操作。如果你的算法复杂度是O(n^2)而n最大是10000那么最坏情况下需要1e8次操作勉强过线如果n最大是100000那1e10次操作肯定超时。你需要优化的算法——从O(n^2)降到O(n log n)通常就够了。怎么降主流的办法就是二分、排序、动态规划、哈希、数据结构等。比如“求数组元素两两之和小于K的个数”暴力两重循环O(n^2)直接超时你先排序再用双指针复杂度立刻变成O(n log n)这就是算法设计的意义所在。内存方面常见的一个坑是程序开了一个int类型的二维数组[10000][10000]那占用的内存是10000100004字节大约400MB绝大多数OJ的内存限制是256MB直接MLE。遇到这种情况要么把数组改成short或bool要么把二维压成一维滚动数组要么换用稀疏存储。在牛客刷题建议每一道题提交之后都看一眼“通过时间”和“内存占用”这两个数据会帮你建立起“复杂度直觉”。做多了你看着数据范围就能猜到这道题应该用什么复杂度的算法。4. 软考、竞赛与求职不同目标下的刷题策略4.1 软考题库刷题与OJ刷题方向完全不同有一类人搜索“牛客刷题”是想备战软考。这里我要把话说明白软考和OJ刷题是两个赛道别混在一起。软考比如软件设计师、程序员等主要考的是理论知识、概念理解、案例分析题目以选择题、简答题为主涉及软件工程、数据库、操作系统、计算机网络等内容。这种考试用牛客的OJ来刷效果其实一般更适合用专门的软考题库App比如市面上评价不错的刷题软件按知识点模块刷选择题反复记忆。那牛客对软考有用吗也有用但仅限于软考中的“程序设计”科目或者下午场的算法题部分。如果你考的是程序员或者软件设计师牛客网上“公共基础知识”和“C语言程序设计”相关题目是可以练的但是不要把牛客当成软考的全部复习材料。正确的姿势是拿软考题库刷基础概念再用牛客练代码手感和算法题。4.2 CSP-J这类竞赛建议按洛谷的节奏来如果你的目标是CSP-J这类信奥竞赛那我建议你认真考虑把主阵地放在洛谷而不是牛客。原因不复杂竞赛的题量和选拔方向跟企业笔试不一样。CSP-J考的是数学思维、算法效率和代码实现能力侧重“在有限时间内写出正确、高效的程序”它不会考你“HTTP返回码有几个”也不会考“进程和线程的区别”这些是企业笔试的常客但竞赛一般不涉及。洛谷的题库和题单是围绕竞赛大纲设计的难度梯度科学题解质量也高。那牛客在竞赛路线里还有位置吗有。当你在洛谷刷题刷累了或者某个算法突然搞不明白的时候牛客上有些题目描述更生活化适合用来调节心情或者作为竞赛入门前的热身。不过核心策略还是竞赛备考用洛谷求职备考用牛客。两边都想要往往两边都搞不好。4.3 笔试冲刺牛客真题的用法如果你已经进入秋招或春招的笔试季我的建议是每天固定抽出一到两个小时专门刷牛客上目标公司的真题。这里的“目标公司”不一定非要大厂你可以先把想去的公司列一个清单然后去牛客题库里搜索它们的名字按时间排序做最近的题目。这样做有两个好处。第一题型命中率高。同一个公司出题人和出题风格往往有一定延续性你做它最近两三年的真题就能找到它常考的考点这种信息在别处不容易找到。第二心理上更稳。当你做过这家公司去年同期的笔试题真的有考试那天看到类似的题不会慌因为你已经提前适应过这个难度。一个推荐的冲刺计划是第一周做5套最近一年的真题目的是“熟悉题型”和“找漏洞”第二周针对错题对应的知识点回到“专题训练”去补基础这就是所谓的“真题暴露漏洞专题补齐短板”第三周再回到整套真题这次要定时按考试节奏做模拟笔试当天的心态和时间分配。三周之后你对自己的水平会有一个很清晰的定位。5. 牛客刷题避坑手册那些实战中踩过的坑5.1 常见OJ报错的含义与排查思路牛客提交之后判题系统会返回各种结果新手经常看到提示就懵。这里整理一个速查表你可以把这张表收藏了以后每次提交都可以对照。判题结果含义常见原因与排查思路AC (Accepted)通过恭喜可以做下一题了WA (Wrong Answer)答案错误算法思路或边界条件有问题检查数据范围、循环边界、特殊样例TLE (Time Limit Exceeded)超时复杂度太高需要优化算法或IO方式MLE (Memory Limit Exceeded)超内存数组开太大、数据结构占用过多考虑压缩存储RE (Runtime Error)运行时错误数组越界、空指针、除零、栈溢出。C/C里RE约等于段错误PE (Presentation Error)格式错误输出多了或少了空格、换行基本是格式问题好改CE (Compile Error)编译错误语法错误、少头文件、命名冲突编译器信息一般会告诉你WA是我见到最多的判题结果也是最让人头秃的。遇到WA的时候不要反复用同一个思路提交这样是在赌运气。正确的排查方式是把题目再读一遍尤其是数据范围、输入格式、输出要求的细节写一个自己能想到的特殊样例比如空数组、单元素、全是0、全是同一个数、边界最大值带进去手动算一遍看结果对不对。我自己的经验是80%的WA都能通过自己构造边界样例找出来。5.2 牛客上的三个高效刷题习惯第一个习惯是“先思考再动手最后看题解”。一道题拿到手给自己设定一个15到20分钟的时间窗口在这段时间里必须独立完成思考。思考不出来的再翻题解但要带着问题去看别人为什么想到了这个方法我自己卡在哪一步了看完题解合上答案自己重新实现一遍。如果不重写你看过的题解在一个星期后基本就忘干净了。第二个习惯是“错题本”。牛客有“做题记录”功能你可以很方便地翻到自己做过的题。我建议每次做完一道有价值的题在旁边写上这道题考了什么知识点我的解法时间复杂度是多少如果数据范围再大十倍我要怎么优化。不用写长两三句话即可但坚持下来一个月后你会发现自己的总结能力明显提升。第三个习惯是“复盘比赛”。牛客上经常有周赛和模拟赛这些比赛除了能检验水平最大的价值是考后复盘。比赛结束后不要只看分数把每道没做出来的题都想办法搞懂搞清楚它属于哪类问题自己当时为什么没思路。这种复盘是性价比极高的学习方式比再刷十道简单题有意义得多。5.3 换语言还是换姿势经常有人问我C语言刷题刷不动了换成Java或者Python会不会好一点这个问题要分情况聊。如果你刷不动是因为输入输出处理不好、指针绕晕了、数组越界找不出来那换语言确实能解决问题因为Java和Python在这些方面都更“宽容”适合把精力集中在算法本身。但如果刷不动是因为一道题读完题目完全没有任何思路那换语言没用问题出在算法积累上你应该往回退一档先刷简单题积累基本题型。我个人对语言的建议是牛客笔试最稳妥的选择是C因为语法简练、性能稳定STL又很强大。Java的代码量偏大笔试时如果时间紧张敲起来会比较吃亏。Python写起来最快但部分OJ对Python不够友好同样的算法可能比C慢近十倍遇到强数据范围容易TLE。所以如果目标明确是国内的互联网公司笔试用C或者JavaPython作为辅助用来快速验证思路。我也见过很多人纠结“要不要上LeetCode”说牛客题太难了。这个问题很简单力扣和牛客都能刷但牛客练代码能力、练笔试适应性力扣练思维、练算法的“内功”。两者不冲突双线并行完全可以。关键是想清楚你现在缺的是哪一块再决定把主要精力放在哪里然后坚持下去。回头看看在牛客刷题的这两年我最大的体会不是“刷了多少题”而是“建立了调试的耐心”。写代码出bug不可怕可怕的是遇到WA就慌看到TLE就乱改。牛客上的每一道题都在培养你面对问题的确定性先分析后动手测试边界验证复杂度——这套方法论其实已经超出了刷题本身的范畴。如果你准备认真刷牛客不妨从今天这篇提到的“先搞懂ACM输入输出”开始把那十几道基础题过一遍再按专题往下走。这条路没什么捷径但每一步都算数。