题目描述(难度⭐⭐)
最近birdfly收到了女友的几份信件,为了只要他俩知道信件的秘密,女友把信件里的每个单词都倒置了。这样只有birdfly将它们倒置过来才能明白女友的心思了。为此birdfly还特意请你编写程序帮他解决一下这个问题。
简单起见假定每封信只包含英文单词和空格,每两个单词之间有一个空格。且长度不超过100,每个单词长度不超过50。输入
输入有多组样例,每组样例输入一行英文(单词和空格)。
输出
对于每组实例输出单词倒置后的结果。每组实例输出占一行。
样例输入
复制I ma yppah yadot oT eb ro ton ot eb I tnaw ot niw eht ecitcarp tsetnoc
样例输出
复制I am happy today To be or not to be I want to win the practice contest
思路:使用栈来逆序输出每行输入中的每个单词,同时保持单词之间的空格不变,处理多实例输入时,利用 while (getline(cin, line)) 循环读取每一行输入,直到输入结束。
了解栈(stack)点此数据结构知识点-CSDN博客
代码1详解
处理多实例输入:
◦ 使用 while (getline(cin, line)) 循环读取每一行输入,直到输入结束。
了解 getline(cin, line)点此C++函数——getline(cin, line)-CSDN博客
◦ 每读取一行输入,调用 solve(line) 函数处理该行输入。
◦ getline(cin, line) 会读取一行输入并存储在字符串 line 中,直到遇到换行符 '\n' 为止。
◦ 如果输入结束(例如用户输入 EOF,即 Ctrl+D(Linux/Mac)或 Ctrl+Z(Windows)), getline 会返回 false,循环结束。
处理单行输入:
◦ 使用一个栈 stack<char> word 来存储每个单词的字符。
◦ 遍历输入的字符串 line,对于每个字符 ch:
■ 如果 ch 是空格,将栈中的字符依次弹出并输出,然后输出一个空格。
■ 如果 ch 是其他字符,将其压入栈中。
◦ 处理完所有字符后,将栈中剩余的字符依次弹出并输出,以处理最后一个单词。
◦ 最后输出一个换行符。
法一(使用c++的数据结构栈)
详细代码
#include <iostream>
#include <string>
#include <stack>
using namespace std;
// 逆序输出每行输入中的每个单词,同时保持单词之间的空格不变
void solve(string line) {
stack<char> word; // 用于存储每个单词的字符
for (char ch : line) { // 遍历输入的字符串
if (ch == ' ') { // 遇到空格
while (!word.empty()) { // 逆序输出当前单词
cout << word.top();
word.pop();
}
cout << " "; // 输出空格
} else {
word.push(ch); // 将字符压入栈中
}
}
// 处理最后一个单词
while (!word.empty()) {
cout << word.top();
word.pop();
}
cout << endl; // 输出换行符
}
int main() {
ios::sync_with_stdio(false); // 优化输入输出
cin.tie(nullptr); // 优化输入输出
string line;
while (getline(cin, line)) { // 读取每一行输入,直到输入结束
solve(line); // 处理每一行输入
}
}
法二(C语言字符数组,自定义reverse反转函数)
用这个方法需要了解字符串输出格式%.*s
点这里了解:%.*s——C语言中printf 函数中的一种格式化输出方式-CSDN博客
版本一(定义全局变量,避开指针传参)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
%%%%%%%%%%%%%%
/\_/\ /\_/\
(* . *)(+ . +)
> # < > $ <
%%%%%%%%%%%%%%
*/
// 声明一个全局字符数组,用于存储输入的字符串
char str[101];
// 反转字符串 str 中从索引 m 到 n 的部分
void reverse(int m, int n) {
for (int i = 0; i < (n - m + 1) / 2; i++) {
// 临时变量,用于交换
char ch = str[m + i];
// 交换前半部分的字符
str[m + i] = str[n - i];
// 交换后半部分的字符
str[n - i] = ch;
}
}
// 处理输入的字符串,将每个单词进行反转
void solve() {
int sr = 0, ed = 0; // sr 和 ed 分别表示当前单词的起始和结束位置
for (int i = 0; str[i] != '\0'; i++) { // 遍历字符串,直到遇到空字符 '\0'
if (str[i] == ' ') { // 如果遇到空格,表示一个单词结束
// 反转当前单词
reverse(sr, ed - 1);
// 输出反转后的单词,单词长度为 ed - sr
printf("%.*s ", ed - sr, str + sr);
// 更新起始位置为下一个单词的开始
sr = i + 1;
// 更新结束位置
ed = i + 1;
} else {
// 如果不是空格,结束位置向后移动
ed++;
}
}
// 处理最后一个单词
reverse(sr, ed - 1);
// 输出反转后的最后一个单词,单词长度为 ed - sr
printf("%.*s\n", ed - sr, str + sr);
}
int main() {
// 读取每一行输入,直到文件结束符
while (gets(str) != NULL) {
// 处理每一行输入
solve();
}
// 程序结束
return 0;
}
版本二(使用指针传参)
/*
%%%%%%%%%%%%%%
/\_/\ /\_/\
(* . *)(+ . +)
> # < > $ <
%%%%%%%%%%%%%%
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 反转字符串 str 中从索引 m 到 n 的部分
void reverse(char *str, int m, int n) {
for (int i = 0; i < (n - m + 1) / 2; i++) {
char ch = str[m + i]; // 临时变量,用于交换
str[m + i] = str[n - i]; // 交换前半部分的字符
str[n - i] = ch; // 交换后半部分的字符
}
}
// 处理输入的字符串,将每个单词进行反转
void solve(char *str) {
int sr = 0, ed = 0; // sr 和 ed 分别表示当前单词的起始和结束位置
for (int i = 0; str[i] != '\0'; i++) { // 遍历字符串,直到遇到空字符 '\0'
if (str[i] == ' ') { // 如果遇到空格,表示一个单词结束
reverse(str, sr, ed - 1); // 反转当前单词
printf("%.*s ", ed - sr, str + sr); // 输出反转后的单词
sr = i + 1; // 更新起始位置为下一个单词的开始
ed = i + 1; // 更新结束位置
} else {
ed++; // 如果不是空格,结束位置向后移动
}
}
// 处理最后一个单词
reverse(str, sr, ed - 1); // 反转最后一个单词
printf("%.*s\n", ed - sr, str + sr); // 输出反转后的最后一个单词
}
int main() {
char str[101]; // 声明一个字符数组,用于存储输入的字符串
while (gets(str) != NULL) { // 读取每一行输入,直到文件结束符
solve(str); // 处理每一行输入
}
return 0; // 程序结束
}
法三(C++字符串,使用自带的reverse函数)
了解 reverse函数点击:C++知识点_c++ std::reverse-CSDN博客
用这个方法需要了解字符串输出格式%.*s
点这里了解:%.*s——C语言中printf 函数中的一种格式化输出方式-CSDN博客
#include<bits/stdc++.h>
using namespace std;
void solve(string& line) {
int st = 0, ed = 0; // st 和 ed 分别表示当前单词的起始和结束位置
for (auto ch : line) { // 遍历字符串中的每个字符
if (ch == ' ') { // 如果遇到空格,表示一个单词结束
reverse(line.begin() + st, line.begin() + ed); // 反转当前单词
printf("%.*s ", ed - st, line.begin() + st); // 输出反转后的单词
st = ed + 1; // 更新起始位置为下一个单词的开始
ed++; // 结束位置向后移动
} else {
ed++; // 如果不是空格,结束位置向后移动
}
}
reverse(line.begin() + st, line.begin() + ed); // 处理最后一个单词
printf("%.*s\n", ed - st, line.begin() + st); // 输出反转后的最后一个单词
}
int main() {
ios::sync_with_stdio(false); // 禁用同步,提高输入输出效率
cin.tie(nullptr); // 解绑 cin 和 cout,提高输入输出效率
string line;
while (getline(cin, line)) { // 读取每一行输入
solve(line); // 处理每一行输入
}
}
详细解释
包含头文件和命名空间
包含 C++ 标准库的所有头文件,方便使用各种功能。
使用标准命名空间,避免每次调用标准库函数时都需要前缀
std::
。定义
solve
函数
初始化变量:
st
和ed
分别表示当前单词的起始和结束位置。遍历字符串:
使用范围基于的
for
循环遍历字符串中的每个字符ch
。了解范围基for循环点击:C++知识点_c++ std::reverse-CSDN博客处理空格:
如果当前字符
ch
是空格,表示一个单词结束。使用
reverse
函数反转当前单词。使用
printf
输出反转后的单词。更新起始位置
st
为下一个单词的开始。结束位置
ed
向后移动一位。处理非空格字符:
如果当前字符
ch
不是空格,结束位置ed
向后移动一位。处理最后一个单词:
循环结束后,处理最后一个单词。
使用
reverse
函数反转最后一个单词。使用
printf
输出反转后的最后一个单词。输出换行符。
定义
main
函数
优化输入输出:
禁用 C++ 和 C 输入输出流的同步,提高输入输出效率。
解绑
cin
和cout
,进一步提高输入输出效率。读取输入:
声明一个字符串变量
line
,用于存储每一行输入。使用
getline
函数读取每一行输入,直到文件结束。调用
solve
函数处理每一行输入。