分数 20
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。
输入格式:
测试输入包含一个测试用例,在一行内给出总长度不超过500 000的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用若干个空格分开。
输出格式:
每个测试用例的输出占一行,输出倒序后的句子,并且保证单词间只有1个空格。
输入样例:
Hello World Here I Come
输出样例:
Come I Here World Hello
感谢杭州电子科技大学李卫明老师修正数据! 感谢浙江工业大学之江学院石洗凡老师修正测试点提示。
代码长度限制
16 KB
时间限制
300 ms
内存限制
64 MB
我的答案:
分析过程:
为了解决这个问题,我们需要首先确定每个单词的起始和结束位置,然后将这些单词按照逆序输出。
一种简单的方法是从后向前读取字符串,并记录单词的起始和结束位置。每当我们从一个非空格字符移动到一个空格字符时,我们就可以确定一个单词的结束位置,然后继续向前读取,直到遇到下一个非空格字符,该位置为单词的起始位置。现在我们可以输出从起始到结束位置的单词,并在输出下一个单词之前添加一个空格。
解题步骤:
- 读入字符串。
- 从字符串的尾部开始遍历。
- 如果找到一个非空格字符,标记为单词的结束位置。
- 继续向前遍历,直到找到一个空格字符或达到字符串的头部,此位置+1即为单词的起始位置。
- 输出从起始位置到结束位置的单词。
- 如果当前位置不是字符串的起始位置,则输出一个空格,并继续从上一步的起始位置-1继续查找下一个单词。
- 重复步骤3-6直到遍历完整个字符串。
C语言:
#include <stdio.h>
#include <string.h>
int main() {
char str[500001];
gets(str); // 读入字符串
int length = strlen(str); // 获取字符串长度
int end, start, isFirst = 1;
for (end = length - 1; end >= 0;) {
if (str[end] != ' ') { // 找到单词的结束位置
start = end;
while (start >= 0 && str[start] != ' ') { // 找到单词的起始位置
start--;
}
start++;
// 输出单词
if (isFirst) {
isFirst = 0;
} else {
printf(" ");
}
for (int i = start; i <= end; i++) {
printf("%c", str[i]);
}
end = start - 2;
} else {
end--;
}
}
return 0;
}
C++:
#include <iostream>
#include <string>
using namespace std;
int main() {
string str;
getline(cin, str); // 读入字符串
int end, start, length = str.length();
bool isFirst = true;
for (end = length - 1; end >= 0;) {
if (str[end] != ' ') {
start = end;
while (start >= 0 && str[start] != ' ') {
start--;
}
start++;
// 输出单词
if (isFirst) {
isFirst = false;
} else {
cout << " ";
}
for (int i = start; i <= end; i++) {
cout << str[i];
}
end = start - 2;
} else {
end--;
}
}
return 0;
}
这两种解决方案基本上是相同的,但是C++版本使用了C++标准库中的字符串处理函数,而C版本使用了C标准库中的函数。
我将逐一解析每个步骤:
1. **读入字符串。**
- 首先,我们需要拥有一个字符串才能开始处理。这一步是获取输入。
2. **从字符串的尾部开始遍历。**
- 为何从尾部开始而不是头部呢?因为我们的目标是将句子的单词顺序反转。从尾部开始遍历可以使我们首先找到最后的单词,这样在输出时,它就变成了第一个单词。
3. **如果找到一个非空格字符,标记为单词的结束位置。**
- 为何是非空格字符?因为英文单词是由字母组成,并用空格分隔。当我们从后向前遍历并遇到第一个非空格字符时,我们知道我们已经找到了一个单词的结束位置。
4. **继续向前遍历,直到找到一个空格字符或达到字符串的头部,此位置+1即为单词的起始位置。**
- 既然我们找到了单词的结束,下一步自然是找到它的开始。从当前位置继续向前遍历,直到遇到一个空格(这意味着单词结束了)或字符串的开始位置(对于第一个单词来说)。记住,我们已经确定了单词的结束位置,所以我们知道单词的起始和结束位置之间的字符构成了这个单词。
5. **输出从起始位置到结束位置的单词。**
- 有了单词的起始和结束位置,我们可以直接输出它。
6. **如果当前位置不是字符串的起始位置,则输出一个空格,并继续从上一步的起始位置-1继续查找下一个单词。**
- 这步确保了单词间只有一个空格。因为我们在输出一个单词后可能有多个空格(例如输入字符串有多个连续的空格),我们跳过这些额外的空格并找到下一个单词的结束位置。
7. **重复步骤3-6直到遍历完整个字符串。**
- 我们将重复这个过程,直到我们处理了字符串中的每一个字符,从而保证了每个单词都被反向输出。
总结:这种方法的关键在于它从尾到头遍历字符串并使用空格作为单词分隔符。在输出时,这确保了我们首先输出的是最后一个单词,然后是倒数第二个单词,以此类推,从而达到了反转单词顺序的目的。
总结:
这道题目的主题是“说反话”,但它实际上涉及了许多基础的编程和数据处理技能。通过这题,我们可以学到以下几点:
1. **字符串操作**:如何遍历、如何标记单词的开始和结束,以及如何根据标记输出子串。
2. **逆序处理**:对数据进行反向处理是一个常见的编程问题,不仅仅局限于字符串。
3. **特定字符的定位与跳过**:在这个场景中,是空格作为分隔符。但在其他上下文中,我们可能需要跳过逗号、制表符或其他字符。
4. **边界条件的处理**:如何处理字符串的开始和结束、如何处理多余的空格等,都是需要考虑的边界条件。
5. **优化处理**:尽管这道题的初级解决方案是从尾到头遍历字符串,但还有其他方法,例如分割字符串并存储在数组或其他数据结构中,然后逆序输出。选择哪种方法取决于具体的需求和约束。
6. **实际应用的启示**:在真实世界的应用中,我们可能需要处理各种文本数据,如日志文件、用户输入等。学会如何有效地处理字符串和文本是任何编程语言中的一个重要技能。
总的来说,这道题目提供了对字符串处理的实践经验,并强调了为何这种能力在实际应用编程中是如此重要。