# 第8课编程题(教师版) ## 本课知识点覆盖表 | 核心知识点 | GESP等级 | 对应课堂题 | |---|---|---| | 字符数组、字符串结束标志、单词与整行输入 | 三级工具 | 课堂1 | | `string` 长度、下标遍历、字符分类统计 | 三级工具 | 课堂2 | | 字符串查找、替换与截取 | 三级工具 | 课堂3 | | 字符串逆序与回文判断 | 三级工具 | 课堂4 | ## 一、课堂练习(4题) ### 课堂1:两种字符串输入【适中】 **题目描述:** 第一行输入一个不含空格的单词,使用字符数组保存;第二行输入一个可能含空格的句子,使用字符串保存。依次输出单词长度、句子长度以及句子中的空格数量。 **输入格式:** 第一行输入一个不含空格的单词;第二行输入一整句话。 **输出格式:** 依次输出单词长度、句子长度和空格数量。 **数据范围:** 单词和句子长度均不超过 200。 **输入样例:** ```text GESP I love C++ ``` **输出样例:** ```text 4 10 2 ``` **解题思路:** 字符数组以 `'\0'` 作为结束标志;读完单词后先忽略换行,再用 `getline` 读取整行字符串。 **参考代码:** ```cpp #include #include 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 #include 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 #include 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 #include #include 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:字符串长度【简单】 **题目描述:** 输入一个不含空格的字符串,输出它的长度。 **输入格式:** 输入一个不含空格的字符串。 **输出格式:** 字符串长度。 **数据范围:** 字符串长度为 1~200。 **输入样例:** ```text orange ``` **输出样例:** ```text 6 ``` **解题思路:** 使用字符串的 `size` 获取长度。 **参考代码:** ```cpp #include #include using namespace std; int main() { string s; cin >> s; cout << s.size(); return 0; } ``` **易错提醒:** 长度是字符个数,最后一个字符的下标是长度减 1。 ### 课后2:统计指定字符【简单】 **题目描述:** 输入一个不含空格的字符串和一个字符,统计该字符出现次数。 **输入格式:** 输入一个字符串和一个待统计字符。 **输出格式:** 指定字符出现次数。 **数据范围:** 字符串长度不超过 200。 **输入样例:** ```text banana a ``` **输出样例:** ```text 3 ``` **解题思路:** 遍历字符串,字符相等时计数。 **参考代码:** ```cpp #include #include 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 #include 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 #include #include 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 #include 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 #include 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 #include 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:连续字符压缩【中等】 **题目描述:** 输入一个仅含英文字母的字符串,将连续相同字符压缩为“字符加次数”。即使只出现一次,也要输出次数。 **输入格式:** 输入一个仅含英文字母且不含空格的字符串。 **输出格式:** 压缩后的字符串。 **数据范围:** 字符串长度为 1~500。 **输入样例:** ```text aaabbcaaaa ``` **输出样例:** ```text a3b2c1a4 ``` **解题思路:** 记录当前连续段的字符和长度;遇到不同字符时输出上一段,最后补输出末段。 **参考代码:** ```cpp #include #include 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:最长回文前缀【略难】 **题目描述:** 输入一个不含空格的字符串,找出从第一个字符开始的最长回文子串并输出。 **输入格式:** 输入一个不含空格的字符串。 **输出格式:** 最长回文前缀。 **数据范围:** 字符串长度为 1~200。 **输入样例:** ```text abacdf ``` **输出样例:** ```text aba ``` **解题思路:** 从整个字符串长度开始递减,检查前缀两端是否对称;第一个成功的就是最长答案。 **参考代码:** ```cpp #include #include 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 #include 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; } ``` **易错提醒:** 只比较字符串长度不够,必须比较每个字母的出现次数。