news 2026/10/5 2:52:43

DHUOJ基础22/23/24题深度拆解:循环、数组与字符处理的避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DHUOJ基础22/23/24题深度拆解:循环、数组与字符处理的避坑指南

一份面对DHUOJ(东华大学在线评测系统)基础题集的深度拆解。写这篇的初衷很简单:基本每届大一学生都会被OJ的22、23、24这三道题卡一下,但又很少有人把它们的共性规律讲明白。这篇文章我会把这三道题背后的判定逻辑、输入输出陷阱、常见扣分点全部摊开讲,尤其是我自己当年在这三题上反复提交才过审的经历,相信对正在刷题的你有直接帮助。

DHUOJ作为学校自建的Online Judge平台,题目编号越靠前,越偏向语法和基础算法。基础的22、23、24正好卡在一个微妙的节点:它不再像前面几题那样让你纯粹打印一个字符串,而是开始要求你接受外部输入、做计算、再按严格格式输出。很多同学就是在这一阶段第一次体会到“本地运行好好的,提交却报错”的滋味。

这篇文章真正适合两类人:一类是刚接触OJ、连题目判定状态(Accepted/Compile Error/Output Limit Exceeded)都还没认全的纯新手;另一类是已经能AC前面简单题,但遇到稍微复杂一点的输入格式就懵圈的备赛者。我会从题型规律、代码模板、避坑经验三个层面来讲,不卖关子,直接上干货。

提示:不同年级的DHUOJ题面可能有微调,但核心考点高度稳定,本文给出的思路对所有基础段题目通用。

1. 基础22、23、24的真正考点:从“会语法”到“会解题”

1.1 三道题在题目序列中的定位

DHUOJ的基础题序列通常是从“输出Hello World”级别的题目开始的,逐步递增难度。到了22、23、24这个编号区间,你仔细观察就会发现一个规律:它们已经不再直接给你完整的输出样本让你模仿,而是把问题描述成了一个“输入若干个数据,输出计算结果”的黑盒模型。

这个转变非常关键。前面那些题,你只要会用printf或cout就能过;但从这三道题开始,你的代码必须具备以下三个新能力:

  • 读取未知数量的输入数据,并正确处理读取结束的情况
  • 根据输入数据做一定逻辑运算,而不是无脑打印
  • 严格按照题目规定的格式输出,多一个空格、少一个换行都会导致判错

很多同学在这三道题上栽跟头,不是因为不会写代码,而是因为“根本没想到OJ是拿隐藏数据来测你的”。你看到的题目描述只是冰山一角,Judge程序会把你提交的代码丢进一组你完全不知道的测试数据里,逐个比对输出结果。

1.2 隐藏数据的判定逻辑:为什么“样例能过”不等于“能AC”

这三道题里最让人抓狂的现象是:样例输入和样例输出明明能对上,点击提交却显示Wrong Answer。原因很简单——你得把代码放到更全面的测试集里去检验。

以我当年刷题的经验为例,OJ的测试数据通常会覆盖几种特殊边界:

  • 最小数据:比如输入为0、1,或者负数
  • 最大数据:比如输入的数值接近int上限
  • 重复数据:比如大量相同的数字
  • 杂乱格式:比如输入中间混着多个连续空格,或者最后一行没有换行

如果代码只针对样例数据做优化,或者某些变量类型选得不对,一旦碰到边界情况就会输出错误结果。基础22、23、24这组题中,最常见的问题就是整数溢出和使用int接收该用long long的数据。

// 错误示范:看似逻辑正确,但遇到大数会溢出 #include <stdio.h> int main() { int a, b; while (scanf("%d %d", &a, &b) != EOF) { printf("%d\n", a + b); } return 0; } // 正确示范:用 long long 接收,稳妥处理大整数 #include <stdio.h> int main() { long long a, b; while (scanf("%lld %lld", &a, &b) != EOF) { printf("%lld\n", a + b); } return 0; }

1.3 三道题背后的“递进关系”

我在帮同专业学弟学妹看代码的时候发现,基础22、23、24实际上是有意安排成递进结构的,它们分别对应了三个不同的能力层级,我做了个简单的对照:

题目编号核心考察点常见出题方向主要坑点
基础22循环与控制流累加求和、数列计算循环边界、数据类型选择
基础23数组与元素处理极值查找、冒泡排序、去重数组下标越界、循环范围
基础24字符与格式处理字符串倒序、字符过滤、ASCII码操作缓冲区遗留换行符、输出格式

这个递进关系并非偶然。22题让你掌握“反复做一件相同的事”的循环思维,23题让你把数据装进容器并进一步加工,24题则从数值处理跳到字符处理,考察你是否具备切换输入类型的能力。一关一关迈过去,你的OJ刷题才真正算入了门。

2. 基础22:循环与累计的套路化拆解

2.1 最可能的题面与通用解题框架

虽然我无法保证你手中那份题面上写的是哪道题,但从多年各种OJ题库的规律来看,基础22这一题通常与“数列求和”脱不开关系。常见的考察形式有:输入一个n,输出1加到n的和;或者输入若干个整数,求其中所有数的总和;以及进阶一点的分组求和。

不管是哪种变形,核心解法都是一套循环累加框架,我把这个框架拆成四步:

  1. 读取一个启动变量(可能是n,也可能是EOF标记)
  2. 初始化一个累加变量为0
  3. 进入循环,反复读取数据并累加
  4. 循环结束后,按照题目要求的格式输出结果

这里有一个非常重要的经验:初始化累加变量为0,不是随便写写,而是为了防止“脏数据”。有些同学图省事,让累加变量沿用声明时未初始化的值,在本地编译器里可能恰好是0,但换个环境可能就是随机值,最终导致结果完全错乱。

#include <stdio.h> int main() { int n; long long sum = 0; // 累加变量务必初始化,且数据类型要够大 scanf("%d", &n); for (int i = 1; i <= n; i++) { sum += i; } printf("%lld\n", sum); return 0; }

2.2 循环边界:小于等于还是小于?

别小看循环条件里这个“等于号”,它在22这类循环题里是分水岭级别的细节。求1到n的和,循环条件写成i < n,结果就变成从1加到n-1,直接少了一项;写成i <= n才是正确的。

我自己总结了一个快速判断方法:先拿小数据手算。比如题目说n=5,预期输出15,你把n=5代入循环里走一遍,如果循环体执行了5次,说明条件写对了;如果只有4次,说明少了等于号。这个方法很笨,但对样例数据非常有效,而且能帮你建立对循环次数的直觉。

还有一种情况很阴险:题目给的样例输入里n是5,你的i < n恰好因为某些原因算出了15以外的错误值,但只要你和正确答案差得不多,在OJ的Wrong Answer提示下你就会琢磨半天。所以我的建议是,循环边界这种细节,不管多简单,都要养成“先手算一遍”的习惯。

2.3 关于EOF读取方式的最佳实践

在基础22这题中,有些版本会要求处理多组输入数据,直到文件结束才停止。此时你用while(scanf(...) != EOF)还是while(cin >> n)取决于语言习惯,但有一个共同的注意事项:千万不要在循环内部对读取失败的情况做多余的假设。

我见过有同学这么写:

while (scanf("%d", &n) == 1) { // 处理过程 }

这个写法本身没问题,scanf返回值为1表示成功读到一个整数。但有同学在while循环里再次调用scanf去读取下一组数据,导致每次循环漏读半个数据。这类错误在本地测试时很难发现,因为样例输入往往组数不多,多读一次碰巧也能读取到下一组开头的数据。

正确的做法是:一次性在循环条件中完成读取动作,循环体内只做业务处理。这既保证了不会漏读,也避免了误读。

3. 基础23:数组操作的边界思维

3.1 从“单点计算”到“容器处理”

如果你已经顺利AC了基础22,那么基础23会给你一种“明显上难度”的感觉。因为它不再是“读一个数,处理一个数,输出一个数”那么简单,而是要求你先读入一整批数据,存进数组,然后再从数组里做筛选、交换、或统计。

这种转变的核心在于:数据不再是一次性消费的流水,而是可以反复访问的集合。

在我个人的刷题经验中,基础23最让人头疼的不是数组的语法,而是访问数组时对下标范围的失控。比如题目要求“有n个整数,找出最大值和最小值”,你没注意数组长度,直接开了int a[10],结果n可能到20,一跑就数组越界。在本地编译器里,越界可能不会立刻报错,只是悄悄改写相邻内存;但提交到OJ上,就可能出现莫名其妙的Runtime Error。

#include <stdio.h> int main() { int n; scanf("%d", &n); int a[n]; // 变长数组,C99标准支持,按输入动态确定大小 for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } int max = a[0]; int min = a[0]; for (int i = 1; i < n; i++) { if (a[i] > max) max = a[i]; if (a[i] < min) min = a[i]; } printf("%d %d\n", max, min); return 0; }

注意:如果OJ编译环境严格遵循C89标准,变长数组可能不被支持。稳妥做法是开一个足够大的固定数组,比如int a[1000],然后只使用前n个元素。这是我在DHUOJ上吃过亏之后学到的教训。

3.2 极值与排序的典型错误:忽略重复元素

基础23还有一种热门变形:让你把n个数排序输出。如果你会写冒泡排序或选择排序,这题本身难度不高;但有一个隐蔽的陷阱是“重复元素”。有些题目会故意输入包含重复值的数组,并要求输出排序后的完整序列。很多同学在排序算法实现时,遇到值相等的情况会做出错误交换,导致输出顺序不稳定,最终被判定为Wrong Answer。

我记得当时有个同学写的选择排序里,判断最小值的条件是<,在遇到重复最小值时下标一直不更新,结果多轮排序后重复元素的位置错乱,但打印出来的数字序列看起来又好像没问题。这种错误非常难发现,唯一的排查方式就是在纸上手动跑一轮数据。

我列一下自己用着最顺手的排序处理思路:

  • 冒泡排序:每一轮把最大的元素“浮”到末尾,只需两层循环
  • 选择排序:每一轮找出未排序部分的最小值,与未排序部分首元素交换
  • C语言快捷方式:直接用qsort函数配合cmp回调,同时注意返回值写法

3.3 输入读取与数组索引的对应关系

基础23里第二常见的错法,是把数组下标从1开始,但循环遍历时从0开始,或者在读取时从0开始但输出时从1开始,导致输出结果中少了一个元素、多了一个未初始化的垃圾值。

建议养成一套固定的书写习惯:读取和遍历都从0开始,数组下标最大用到n-1。这种操作虽然在C语言里和“从1开始”的直觉有点不同,但它能最大程度地避免混乱。如果你执意要从1开始存放,那遍历时也要保持从1到n,千万不要混着来。

4. 基础24:字符与格式处理的两个隐形坑

4.1 缓冲区混合输入:字符为什么读不到

基础24大概率会把方向切换到字符处理上,比如统计一段字符串中某个字符的出现次数、把字符串倒序输出,或者过滤掉非字母字符。这类题目本身的逻辑并不复杂,真正让大批人交白卷的,而是C语言中处理字符与数字混合输入时的缓冲区问题。

想象这样一个场景:先输入一个整数n,然后再输入n个字符,最后把这n个字符倒序输出。如果你直接用scanf("%d", &n)读取整数,接着用scanf("%c", &ch)循环读取字符,你会惊讶地发现:第一次读字符时,竟然读到了一个换行符。这是因为您按下回车后,换行符'\n'还残留在输入缓冲区里,被下一个scanf("%c")直接吃掉了。

4.2 彻底根治缓冲区残留:getchar的妙用

解决这个问题最常用的方式有两种:

第一种,在读取整数后主动吃掉残留的换行符:

scanf("%d", &n); getchar(); // 吃掉输入流中的换行符 for (int i = 0; i < n; i++) { scanf("%c", &ch); }

第二种,使用scanf(" %c", &ch),在格式符前面加一个空格。这个空格能让scanf自动跳过所有空白字符(包括空格、换行、制表符),从而直接读到真正的字符。

这两种方法我都在DHUOJ上验证过,都能稳定通过判题。但个人更推荐第二种,因为不需要额外记忆“什么时候该加getchar”,只要在读取字符时养成加空格的习惯就行。

4.3 输出格式:空格与换行的“和珅式”考究

字符处理题的另一个隐形坑是输出格式。很多时候题目要求“输出每个字符,字符之间用空格隔开”,但很多同学在循环里无脑地每输出一个字符就加一个空格,导致最后一个字符后面多了一个尾随空格。在OJ判定中,多余的尾随空格和缺少换行一样,都会直接判为Presentation Error或Wrong Answer,非常冤。

我的处理套路是:判断当前元素是否最后一个,如果是,则只输出元素;如果不是,则输出“元素+空格”。或者更简洁一点,在第一个元素前不输出空格,之后的元素前都加一个空格。

写成代码大概是这个形态:

for (int i = n - 1; i >= 0; i--) { if (i == n - 1) { printf("%c", str[i]); } else { printf(" %c", str[i]); } } printf("\n");

5. 从22、23、24延伸出去的刷题方法论

5.1 一套万能的题目拆解流程

你可能会觉得,不就是三道基础题嘛,AC掉就完了。但根据我带过的学生反馈来看,很多人在22、23、24这三题上耗费了大量提交次数,却依然没有总结出通用套路,以致于后面遇到稍微复杂一点的题就又开始手足无措。

所以我真正想借这三道题传递的不是答案,而是一套解题流程,我称之为“三步拆题法”:

  1. 读题后先圈定输入格式和输出格式,明确“程序需要处理几组数据”“数据以什么分隔”
  2. 确定算法核心:是循环累加,还是数组操作,还是字符转换
  3. 在本地测试中,除了样例数据,再手动增加一组边界数据,比如最小值和最大值,验证程序不会崩溃或溢出

这套流程听着简单,但真正执行下去很考验耐心。比如很多人输完样例看到输出正确,就兴冲冲地提交,结果被Wrong Answer打脸。如果你养成了“先测边界再提交”的习惯,大部分基础段的错误都能在本地提前拦住。

5.2 错题本的真正用法:记录判定状态而非只记题目

我在刷DHUOJ的初期,建了一个简单的文本笔记,每道错题记录三列内容:题目编号、第一次提交的判定状态、错误原因。后来我发现这个习惯的价值远超预期——因为人很容易在同一个坑里反复掉进去,比如“忘记初始化累加变量”“字符读取没跳过换行”“最后多输出了一个空格”,这些如果不刻意记录,下一次遇到相似题时大概率还会再犯。

记录判定状态还有一个额外好处:你可以逐渐摸清OJ的脾气。比如看到Compile Error,你就知道是语法问题;看到Runtime Error,就能猜出可能是数组越界或除零;看到Time Limit Exceeded,就说明算法复杂度太高,需要换思路。这些判断能力,都是靠一笔一笔记录练出来的。

5.3 如何判断是否进入下一题:不是AC就行

很多人觉得,OJ刷题就是“AC一道,下一道”,其实这个节奏对新手并不友好。以我的经验来看,评判一道题是否真正掌握,至少要满足两个条件:

  • 你能在不看任何参考代码的情况下,把代码完整默写出来
  • 你能跟身边同学讲清楚这道题的关键细节和潜在坑点

如果你只是照着题解敲了一遍,提交通过了,那其实意义不大。因为OJ题目成千上万,你最终要的不是某几道题的答案,而是处理问题的思维框架。22、23、24这三题恰好是框架养成的起点,走稳一点,后面会轻松很多。

6. 我在这些基础题上踩过的坑和最终建议

6.1 一个记忆犹新的“Presentation Error”教训

讲一个我自己的真实经历。大一刷基础22时,我第一次提交就看到了绿色的Accepted,心里还挺得意。但到了基础24的字符倒序题,我连续五次都因为输出格式不对被判了Presentation Error,本地运行却完全看不出问题。

后来我才发现,题目要求“每行末尾不能有多余空格”,而我恰好是在倒序输出时,把每个字符后都加了一个空格。系统认为你数字对了、顺序对了,但格式和标准答案有出入,就给你一个专门提示格式错误的判定。那次之后我再也没有犯过尾随空格的错误,但也因此长了个记性:在OJ面前,格式不是细枝末节,而是正确性的一部分。

6.2 建议初学者设立的小目标

如果你现在刚开始接触DHUOJ,我的建议是先别急着追求提交速度和AC数量。基础22、23、24这组题目本身就是绝佳的练习素材,你可以给自己定三个小目标:

  • 目标一:三道题全部独立完成,过程中不参考题解,允许查阅语法手册
  • 目标二:用至少两种不同的写法实现同一道题(比如C语言和Python各写一遍)
  • 目标三:把每道题涉及的知识点用一个简单的思维导图整理出来,比如“数组越界”“缓冲区残留”“尾随空格”

这三个目标都完成之后,你会明显觉得自己的代码调试能力上了一个台阶,后面再遇到其他OJ平台的题目,也不会被陌生环境吓到。

6.3 最后一句话:保持随手测试的习惯

回到基础22、23、24这三道题本身,我相信你在完整看完这篇文章后,已经对它们背后隐藏的考点有了更清晰的认知。无论是循环边界、数组下标、还是字符缓冲区,这些坑都是可以提前避开的。但所有理论最终要靠实践来巩固,保持“写完就在本地多测几组数据”的习惯。

我的一个现实体会是:OJ刷题这件事,前期最大的障碍往往不是智商,而是粗糙。这三道基础题,本质上就是在训练你把代码写严谨的能力。你越早意识到这一点,越能避免在以后的算法题上因为低级失误反复重交。祝你在DHUOJ上顺利拿下这三个基础关,下一步的进阶之路会平坦很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 2:52:41

Shell函数实战:用Nginx管理脚本掌握代码复用

1. 为什么把函数单独拎出来讲1.1 函数是Shell脚本从"命令流水账"到"程序"的分水岭前面几篇我们一直在处理命令、变量、条件判断和循环&#xff0c;说白了还是在写"命令流水账"。真正让Shell脚本具备工程价值的&#xff0c;是函数。没有函数之前&…

作者头像 李华
网站建设 2026/10/5 2:52:40

NopCommerce二次开发缓存架构实战:从接口到失效策略

做NopCommerce二次开发这几年&#xff0c;最让我觉得值回票价的部分就是它的缓存架构。NopCommerce 4.9.3的全栈开发实战做到第3.4章节&#xff0c;已经不满足于单纯讲“怎么调接口、怎么写页面”&#xff0c;而是要回答一个更关键的问题&#xff1a;当用户请求打到服务器上&am…

作者头像 李华
网站建设 2026/10/5 2:50:22

Claude Code实战指南:代理式AI编码工具的安装配置与高效工作流

最近一段时间&#xff0c;我几乎每天都会被问到同一个问题&#xff1a;Claude Code到底是什么&#xff0c;为什么大家都在折腾它&#xff1f;作为命令行重度用户&#xff0c;我其实很能理解这种热度——Claude Code和过往那些聊天式AI工具完全是两种物种。它不是又一个问一句答…

作者头像 李华
网站建设 2026/10/5 2:50:11

GPU租用省钱攻略:搞懂计费模式与隐性成本,避开租用暗坑

盯着价格表选GPU租用&#xff0c;是我见过新手最容易犯的错误。第一次租GPU跑深度学习训练的时候&#xff0c;我花了整整一个下午把各种卡片的价格抄了一遍&#xff0c;兴冲冲选了最便宜的一款入门卡&#xff0c;结果一个LoRA微调任务跑了三遍才跑通&#xff1a;第一次显存溢出…

作者头像 李华
网站建设 2026/10/5 2:50:05

长江存储(长存)企业级SSD深度解析:PE510性能、能效与市场竞争力

目录 1. 引言 2. 长江存储&#xff08;长存&#xff09;企业级SSD产品矩阵 3. 核心技术架构 关键术语速查表 4. 性能指标分析 5. 可靠性与数据安全 6. 与市场主流产品对比 7. 市场定位与竞争优势 8. 总结与展望 1. 引言 随着企业级存储对性能、容量和能效的要求不断提…

作者头像 李华
网站建设 2026/10/5 2:49:27

【千问】 无门槛券申领通道,外卖打车都能用,限新人

先把千问这个APP弄在手机里&#xff0c;然后在对话框里输入10月专属口令内容&#xff08;新人6598&#xff09;后&#xff0c;会看到"待领取"按钮&#xff0c;按照页面指引完成账号绑定&#xff0c;成功后8面额的券就会自动发放到你的卡包中&#xff0c;整个流程也就…

作者头像 李华