Files
project1/第08课-字符串与string/编程题-教师版.md

656 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第8课编程题教师版
## 本课知识点覆盖表
| 核心知识点 | GESP等级 | 对应课堂题 |
|---|---|---|
| 字符数组、字符串结束标志、单词与整行输入 | 三级工具 | 课堂1 |
| `string` 长度、下标遍历、字符分类统计 | 三级工具 | 课堂2 |
| 字符串查找、替换与截取 | 三级工具 | 课堂3 |
| 字符串逆序与回文判断 | 三级工具 | 课堂4 |
## 一、课堂练习4题
### 课堂1两种字符串输入【适中】
**题目描述:** 第一行输入一个不含空格的单词,使用字符数组保存;第二行输入一个可能含空格的句子,使用字符串保存。依次输出单词长度、句子长度以及句子中的空格数量。
**输入格式:** 第一行输入一个不含空格的单词;第二行输入一整句话。
**输出格式:** 依次输出单词长度、句子长度和空格数量。
**数据范围:** 单词和句子长度均不超过 200。
**输入样例:**
```text
GESP
I love C++
```
**输出样例:**
```text
4 10 2
```
**解题思路:** 字符数组以 `'\0'` 作为结束标志;读完单词后先忽略换行,再用 `getline` 读取整行字符串。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
char word[205];
string sentence;
cin >> word;
cin.ignore();
getline(cin, sentence);
int wordLength = 0;
while (word[wordLength] != '\0') wordLength++;
int spaces = 0;
for (char c : sentence) {
if (c == ' ') spaces++;
}
cout << wordLength << " " << sentence.size() << " " << spaces;
return 0;
}
```
**易错提醒:** `cin` 不会读入空格;`getline` 前要处理输入缓冲区中的换行符。
### 课堂2字符串分类统计【适中】
**题目描述:** 输入一整行字符串,统计大写字母、小写字母、数字、空格和其他字符的数量。
**输入格式:** 输入一整行字符串。
**输出格式:** 依次输出五类字符的数量。
**数据范围:** 字符串长度不超过 500。
**输入样例:**
```text
Hi 2026!
```
**输出样例:**
```text
1 1 4 1 1
```
**解题思路:** 使用下标遍历字符串,通过互斥分支判断字符所属类别。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
getline(cin, s);
int upper = 0, lower = 0, digit = 0, space = 0, other = 0;
for (int i = 0; i < (int)s.size(); i++) {
char c = s[i];
if (c >= 'A' && c <= 'Z') upper++;
else if (c >= 'a' && c <= 'z') lower++;
else if (c >= '0' && c <= '9') digit++;
else if (c == ' ') space++;
else other++;
}
cout << upper << " " << lower << " " << digit << " "
<< space << " " << other;
return 0;
}
```
**易错提醒:** 字符串的合法下标为 0 到长度减 1分类时只能让一个字符进入一个计数器。
### 课堂3敏感词替换与截取【适中】
**题目描述:** 输入一个不含空格的原字符串、待查找字符串和替换字符串。将原字符串中第一次出现的待查找内容替换掉,并输出替换结果;若未找到,输出 `NOT FOUND`。找到时还要输出替换位置之前的前缀。
**输入格式:** 依次输入原字符串、待查找字符串和替换字符串,三者均不含空格。
**输出格式:** 找到时第一行输出替换后的字符串,第二行输出原字符串中匹配位置之前的部分;未找到时输出 `NOT FOUND`
**数据范围:** 每个字符串长度不超过 200。
**输入样例:**
```text
abc123abc 123 XYZ
```
**输出样例:**
```text
abcXYZabc
abc
```
**解题思路:**`find` 获得首次位置;用 `replace` 替换,用 `substr` 截取前缀。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string source, target, replacement;
cin >> source >> target >> replacement;
size_t position = source.find(target);
if (position == string::npos) {
cout << "NOT FOUND";
} else {
string prefix = source.substr(0, position);
source.replace(position, target.size(), replacement);
cout << source << "\n" << prefix;
}
return 0;
}
```
**易错提醒:** 未找到时 `find` 返回 `string::npos`,不能直接拿这个位置去替换或截取。
### 课堂4忽略格式的回文句【适中】
**题目描述:** 输入一整行字符串,忽略空格和英文字母大小写后,判断它是否为回文串。
**输入格式:** 输入一整行字符串。
**输出格式:** 是回文串输出 `YES`,否则输出 `NO`
**数据范围:** 字符串长度不超过 500只含英文字母和空格。
**输入样例:**
```text
Never odd or even
```
**输出样例:**
```text
YES
```
**解题思路:** 先构造一个无空格、全小写的新字符串,再用左右下标向中间比较。
**参考代码:**
```cpp
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s, cleaned;
getline(cin, s);
for (char c : s) {
if (c != ' ') cleaned += (char)tolower(c);
}
bool palindrome = true;
int left = 0, right = (int)cleaned.size() - 1;
while (left < right) {
if (cleaned[left] != cleaned[right]) {
palindrome = false;
break;
}
left++;
right--;
}
cout << (palindrome ? "YES" : "NO");
return 0;
}
```
**易错提醒:** 比较前必须统一大小写;空字符串和单字符都属于回文串。
## 二、课后作业3题
### 课后1字符串长度【简单】
**题目描述:** 输入一个不含空格的字符串,输出它的长度。
**输入格式:** 输入一个不含空格的字符串。
**输出格式:** 字符串长度。
**数据范围:** 字符串长度为 1200。
**输入样例:**
```text
orange
```
**输出样例:**
```text
6
```
**解题思路:** 使用字符串的 `size` 获取长度。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
cout << s.size();
return 0;
}
```
**易错提醒:** 长度是字符个数,最后一个字符的下标是长度减 1。
### 课后2统计指定字符【简单】
**题目描述:** 输入一个不含空格的字符串和一个字符,统计该字符出现次数。
**输入格式:** 输入一个字符串和一个待统计字符。
**输出格式:** 指定字符出现次数。
**数据范围:** 字符串长度不超过 200。
**输入样例:**
```text
banana a
```
**输出样例:**
```text
3
```
**解题思路:** 遍历字符串,字符相等时计数。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
char target;
int count = 0;
cin >> s >> target;
for (char c : s) {
if (c == target) count++;
}
cout << count;
return 0;
}
```
**易错提醒:** 字符使用单引号概念,字符串使用双引号概念。
### 课后3字符串逆序【简单】
**题目描述:** 输入一个不含空格的字符串,将它逆序输出。
**输入格式:** 输入一个不含空格的字符串。
**输出格式:** 逆序后的字符串。
**数据范围:** 字符串长度不超过 200。
**输入样例:**
```text
GESP
```
**输出样例:**
```text
PSEG
```
**解题思路:** 从最后一个下标向 0 倒序输出。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
for (int i = (int)s.size() - 1; i >= 0; i--) cout << s[i];
return 0;
}
```
**易错提醒:** 倒序循环变量应使用有符号整数,否则减到 0 以下时可能出错。
## 三、扩展练习7题
### 扩展1大小写交替转换【基础综合】
**题目描述:** 输入一个不含空格的字符串,把大写字母转成小写、小写字母转成大写,其他字符保持不变。
**输入格式:** 输入一个不含空格的字符串。
**输出格式:** 转换后的字符串。
**数据范围:** 字符串长度不超过 200。
**输入样例:**
```text
AbC123xY
```
**输出样例:**
```text
aBc123Xy
```
**解题思路:** 遍历并按 ASCII 范围判断,分别调用大小写转换函数。
**参考代码:**
```cpp
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s;
cin >> s;
for (char &c : s) {
if (c >= 'A' && c <= 'Z') c = (char)tolower(c);
else if (c >= 'a' && c <= 'z') c = (char)toupper(c);
}
cout << s;
return 0;
}
```
**易错提醒:** 数字和符号不要改变。
### 扩展2删除指定字符【基础综合】
**题目描述:** 输入一整行字符串和一个字符,删除字符串中所有该字符后输出结果。
**输入格式:** 第一行输入一整行字符串;第二行输入待删除字符。
**输出格式:** 删除后的字符串。
**数据范围:** 原字符串长度不超过 500。
**输入样例:**
```text
a cat and a hat
a
```
**输出样例:**
```text
ct nd ht
```
**解题思路:** 构造新字符串,只加入不等于目标的字符。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s, answer;
char target;
getline(cin, s);
cin >> target;
for (char c : s) {
if (c != target) answer += c;
}
cout << answer;
return 0;
}
```
**易错提醒:** 删除字符后空格仍需保留。
### 扩展3单词数量【中等】
**题目描述:** 输入一整行英文句子,单词之间可能有多个空格,统计单词数量。
**输入格式:** 输入一整行英文句子。
**输出格式:** 单词数量。
**数据范围:** 句子长度不超过 500只含英文字母和空格。
**输入样例:**
```text
I love Cpp
```
**输出样例:**
```text
3
```
**解题思路:** 当当前位置是字母,且它是首字符或前一个字符为空格时,说明一个新单词开始。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
getline(cin, s);
int count = 0;
for (int i = 0; i < (int)s.size(); i++) {
if (s[i] != ' ' && (i == 0 || s[i - 1] == ' ')) count++;
}
cout << count;
return 0;
}
```
**易错提醒:** 不能用空格数加一,因为句首、句尾和连续空格都会造成错误。
### 扩展4查找所有位置【中等】
**题目描述:** 输入原字符串和一个字符,输出该字符出现的所有位置,位置从 1 开始;若没有出现,输出 `NONE`
**输入格式:** 输入一个不含空格的字符串和一个待查找字符。
**输出格式:** 所有出现位置或 `NONE`
**数据范围:** 字符串长度不超过 500。
**输入样例:**
```text
mississippi s
```
**输出样例:**
```text
3 4 6 7
```
**解题思路:** 完整遍历而不提前结束,每次匹配都输出当前位置加一。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
char target;
cin >> s >> target;
int count = 0;
for (int i = 0; i < (int)s.size(); i++) {
if (s[i] == target) {
if (count) cout << " ";
cout << i + 1;
count++;
}
}
if (count == 0) cout << "NONE";
return 0;
}
```
**易错提醒:** 题目要求所有位置,不能找到第一个后使用 `break`
### 扩展5连续字符压缩【中等】
**题目描述:** 输入一个仅含英文字母的字符串,将连续相同字符压缩为“字符加次数”。即使只出现一次,也要输出次数。
**输入格式:** 输入一个仅含英文字母且不含空格的字符串。
**输出格式:** 压缩后的字符串。
**数据范围:** 字符串长度为 1500。
**输入样例:**
```text
aaabbcaaaa
```
**输出样例:**
```text
a3b2c1a4
```
**解题思路:** 记录当前连续段的字符和长度;遇到不同字符时输出上一段,最后补输出末段。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
char current = s[0];
int count = 1;
for (int i = 1; i < (int)s.size(); i++) {
if (s[i] == current) {
count++;
} else {
cout << current << count;
current = s[i];
count = 1;
}
}
cout << current << count;
return 0;
}
```
**易错提醒:** 循环结束后最后一段尚未输出,必须单独处理。
### 扩展6最长回文前缀【略难】
**题目描述:** 输入一个不含空格的字符串,找出从第一个字符开始的最长回文子串并输出。
**输入格式:** 输入一个不含空格的字符串。
**输出格式:** 最长回文前缀。
**数据范围:** 字符串长度为 1200。
**输入样例:**
```text
abacdf
```
**输出样例:**
```text
aba
```
**解题思路:** 从整个字符串长度开始递减,检查前缀两端是否对称;第一个成功的就是最长答案。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
for (int length = (int)s.size(); length >= 1; length--) {
bool palindrome = true;
for (int left = 0, right = length - 1; left < right;
left++, right--) {
if (s[left] != s[right]) {
palindrome = false;
break;
}
}
if (palindrome) {
cout << s.substr(0, length);
break;
}
}
return 0;
}
```
**易错提醒:** 检查的是从下标 0 开始的前缀,不是任意位置的回文子串。
### 扩展7两串是否由相同字母组成【略难】
**题目描述:** 输入两个只含小写字母的字符串,判断它们是否包含完全相同的字母及出现次数,字符顺序可以不同。
**输入格式:** 输入两个只含小写字母且不含空格的字符串。
**输出格式:** 满足条件输出 `YES`,否则输出 `NO`
**数据范围:** 每个字符串长度不超过 500。
**输入样例:**
```text
listen silent
```
**输出样例:**
```text
YES
```
**解题思路:** 使用长度为 26 的计数数组;遍历第一个字符串时加一,遍历第二个时减一,最后全部为零才匹配。
**参考代码:**
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string a, b;
cin >> a >> b;
int count[26] = {0};
for (char c : a) count[c - 'a']++;
for (char c : b) count[c - 'a']--;
bool same = true;
for (int i = 0; i < 26; i++) {
if (count[i] != 0) {
same = false;
break;
}
}
cout << (same ? "YES" : "NO");
return 0;
}
```
**易错提醒:** 只比较字符串长度不够,必须比较每个字母的出现次数。