1. 题目解析与解题思路
这道题目要求我们在一段给定的文本中找出最长的单词和最短的单词。看似简单,但其中包含了字符串处理的多个核心知识点。我们先来看题目具体要求:
输入是一个包含多个单词的字符串,单词之间用空格或逗号分隔。输出需要给出这段文本中最长的单词和最短的单词,每个单词占一行。如果存在多个最长或最短单词,输出第一个出现的。
在实际解题时,我发现有几个关键点需要注意:
- 连续的分隔符(比如多个空格或逗号连在一起)不应该产生空单词
- 最后一个单词后面可能没有分隔符
- 需要准确统计每个单词的长度
2. 字符数组解法详解
我们先来看使用字符数组的解法,这是C语言风格的字符串处理方式,也是很多竞赛选手的入门选择。
#include<bits/stdc++.h> using namespace std; int main() { char s[205][105]; // 二维数组保存单词 char c; // 当前读取的字符 int w = 0, j = 0; // w:单词编号 j:字符位置 while((c = getchar()) != '\n') { if(c != ' ' && c != ',') { s[w][j++] = c; // 存储字符到当前单词 } else if(j != 0) { // 遇到分隔符且当前有单词 s[w][j] = '\0'; // 添加字符串结束符 w++; // 准备下一个单词 j = 0; } } s[w][j] = '\0'; // 处理最后一个单词 w++; int wordNum = w; // 单词总数 int maxlen = 0, minlen = 200; // 初始化长度 int max_i, min_i; // 记录位置 for(int i = 0; i < wordNum; ++i) { int len = strlen(s[i]); if(len > maxlen) { max_i = i; maxlen = len; } if(len < minlen) { min_i = i; minlen = len; } } puts(s[max_i]); puts(s[min_i]); return 0; }这个解法的核心思路是:
- 使用二维字符数组存储分割后的单词
- 逐个字符读取输入,遇到分隔符时完成当前单词
- 遍历所有单词,比较长度找出最长和最短的
我在实际测试时发现几个容易出错的地方:
- 忘记处理最后一个单词(因为可能没有结尾分隔符)
- 没有处理连续分隔符的情况(会导致空单词)
- 数组大小设置不合理可能导致越界
3. string类解法详解
对于C++选手来说,使用string类会让代码更加简洁和安全。下面是用string实现的版本:
#include<bits/stdc++.h> using namespace std; int main() { string s, word, maxWord, minWord; getline(cin, s); s += ' '; // 统一处理 int wst = 0, wlen = 0; // 单词起始位置和长度 int minLen = 200, maxLen = 0; for(int i = 0; i < s.length(); ++i) { if(s[i] == ' ' || s[i] == ',') { if(wlen > 0) { // 有有效单词 word = s.substr(wst, wlen); if(wlen > maxLen) { maxWord = word; maxLen = wlen; } if(wlen < minLen) { minWord = word; minLen = wlen; } } wst = i + 1; // 下一个单词起始 wlen = 0; } else { wlen++; // 增加当前单词长度 } } cout << maxWord << endl; cout << minWord << endl; return 0; }这个版本有几个优势:
- 不需要手动管理内存和数组大小
- 使用substr方法简化了单词提取
- 自动处理字符串长度等操作
在实际编码时,我建议初学者注意:
- string的substr方法参数是(起始位置, 长度)而不是结束位置
- 统一在字符串末尾添加分隔符可以简化逻辑
- 使用getline读取整行而不是逐个字符
4. 常见错误与调试技巧
在解决这类字符串处理题目时,新手常会遇到以下问题:
边界条件处理不当:
- 字符串开头就是分隔符
- 字符串结尾没有分隔符
- 连续多个分隔符
长度统计错误:
- 忘记字符串结束符'\0'不算在长度内
- 中英文混排时字符计数问题
数组越界:
- 没有预留足够的空间给结束符
- 单词数量超出预设数组大小
调试技巧分享:
- 使用cout在关键位置输出中间变量值
- 对于边界情况,可以手动构造测试用例
- 在OpenJudge上提交前,先在本地测试各种情况
我常用的测试用例包括:
- 空字符串
- 只有一个单词的字符串
- 所有单词长度相同的字符串
- 包含多个连续分隔符的字符串
- 包含标点符号的字符串
5. 性能优化与扩展思考
虽然这道题的数据规模不大,但养成良好的编程习惯很重要。我们可以考虑:
时间复杂度优化:
- 当前解法已经是O(n)最优
- 可以边分割边记录,避免二次遍历
空间优化:
- 不需要存储所有单词,只需记录当前最长最短
- 使用滑动窗口思想减少内存使用
功能扩展:
- 处理更多分隔符(如分号、句号)
- 输出所有最长/最短单词
- 统计单词长度分布
对于想进一步提高的同学,可以尝试:
- 实现一个通用的字符串分割函数
- 处理Unicode字符和多字节编码
- 用正则表达式实现相同功能
6. 竞赛技巧与学习建议
在信息学竞赛中,字符串处理是基础但重要的技能。我的备赛建议是:
掌握两种字符串表示方式:
- C风格字符数组:更底层,需要理解指针和内存
- C++ string类:更安全易用,但要知道内部原理
熟练使用关键函数:
- strlen, strcmp, strcpy等C函数
- string的find, substr, erase等方法
多做针对性练习:
- OpenJudge上有大量字符串处理题目
- 从简单题开始,逐步提高难度
建立自己的代码模板:
- 字符串分割
- 模式匹配
- 字符串转换
在准备NOI竞赛时,我会把这类基础题目反复练习,直到能够快速准确地写出无bug的代码。记住,竞赛中基础题的稳定发挥是关键。